记录一下c#学习笔记吧,编译软件下载Visual Studio Installer
注释
单行注释快捷键: (ctrl + k ctrl + l)
取消单行注释:(ctrl + k ctrul + u)
Hello World!
using System; // 使用System命名空间
namespace ConsoleApp // 命名空间
{
class demo // 定义类,类名为demo
{
static void Main(string[] args) // c#的入口函数
{
Console.Write("Hello World!");
Console.WriteLine("hello world!");
}
}
}
Main方法是 C# 应用程序的入口点。
Write和WriteLine的区别是:Write输出不会换行,WriteLine会换行。
控制台输出
Console.Write("Hello World!");
Console.WriteLine("hello world!");
控制台输入
Console.ReadLine()
// 输入一行数据,会等到按下回车为一行输入结束,继续向下执行。 接收到的为字符串,如果想要转换为数值型的可以使用Convert.ToInt32(<要转换的变量>);
Console.ReadKey();
// 一次只读取一个字符,当用户按下任意字符才会继续向下执行。
数据类型
在c#中数据类型分为三种:
1. 值类型
2. 引用类型
3. 指针类型
值类型
| 类型 | 描述 | 范围 | 默认值 |
|---|---|---|---|
| bool | 布尔值 | True 或 False | False |
| byte | 8 位无符号整数 | 0 到 255 | 0 |
| char | 16 位 Unicode 字符 | U +0000 到 U +ffff | '\0' |
| decimal | 128 位精确的十进制值,28-29 有效位数 | (-7.9 x 1028 到 7.9 x 1028) / 100 到 28 | 0.0M |
| double | 64 位双精度浮点型 | (+/-)5.0 x 10-324 到 (+/-)1.7 x 10308 | 0.0D |
| float | 32 位单精度浮点型 | -3.4 x 1038 到 + 3.4 x 1038 | 0.0F |
| int | 32 位有符号整数类型 | -2,147,483,648 到 2,147,483,647 | 0 |
| long | 64 位有符号整数类型 | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 | 0L |
| sbyte | 8 位有符号整数类型 | -128 到 127 | 0 |
| short | 16 位有符号整数类型 | -32,768 到 32,767 | 0 |
| uint | 32 位无符号整数类型 | 0 到 4,294,967,295 | 0 |
| ulong | 64 位无符号整数类型 | 0 到 18,446,744,073,709,551,615 | 0 |
| ushort | 16 位无符号整数类型 | 0 到 65,535 | 0 |
// 常用的几种数据类型
int a= 3; // 整型
float b = 3.5f; // 浮点型,数据后面需要加上f或者F
bool c = false; // 布尔类型
char d = 'a'; // 字符型(单引号为字符型)
string e = "11232eee"; // 字符串类型(双引号为字符串型)
// 可以用sizeof来查看具体类型所占字节数
Console.WriteLine("Size of int: {0}", sizeof(int));
数据类型转换
C# 是一门强类型语言,对类型要求比较严格,但是在一定的条件下也是可以相互转换的,数据类型转换分为两种一种是隐式类型转换,另一种是显示类型转换。
//隐式数据类型转换
int a = 1;
double b = a;
// 显示数据类型转换
double a = 1;
int b = (int)a;
常用的数据类型转换方法
// Parse方法
对于string类型是互相兼容的数据类型,将string类型转换为任意基本类型。
string a = "34583764586438756";
int b = int.Parse(a);
double c = double.Parse(a);
// Convert类型转换能够将任意数据类型转换为任意类型
Convert.ToInt32(<要转换的变量>); // 转换为整型(int)
Convert.等....
隐式类型转换是安全的的,属于低精度转向高精度,显示转换需要强制转换,可能会造成精度丢失。
引用类型
对象类型
对象类型是 C# 通用类型系统中所有数据类型的终极基类。Object是System.Object类的别名。所以对象类型可以被分配任何其他类型(值类型、引用类型、预定义类型或用户自定义类型)的值。但是,在分配值之前,需要先进行类型转换。当一个值类型转换为对象类型时,则被称为 装箱;另一方面,当一个对象类型转换为值类型时,则被称为 拆箱。
object obj;
obj = 100; // 这是装箱
int x = (int)obj; // 这是拆箱
动态类型
可以存储任何类型的值在动态数据类型变量中。这些变量的类型检查是在运行时发生的。与对象类型相似,但是对象类型变量的类型检查是在编译时发生的,而动态类型变量的类型检查是在运行时发生的。
dynamic <变量名> = value;
字符串类型
字符串类型允许给变量分配任何字符串值。字符串类型是 System.String 类的别名。它是从对象(Object)类型派生的。字符串(String)类型的值可以通过两种形式进行分配:引号和 @引号。
string str = @"C:\Windows";
加上@符号,这被称为"逐字字符串",他可以将转义字符变成普通字符使用(空格,换行符等也会被计算在其中),如果需要在里面输出一个引号则需要写一对引号,如下:
string x = @"123\123""123"; // 123\123"123
指针类型
C# 为了类型安全,默认并不支持指针。但是也并不是说 C# 不支持指针,我们可以使用unsafe关键词,开启不安全代码(unsafe code)开发模式。在不安全模式下,我们可以直接操作内存,这样就可以使用指针了。在不安全模式下,CLR并不检测unsafe代码的安全,而是直接执行代码。unsafe代码的安全需要开发人员自行检测。
// unsafe 关键词的使用
// 声明整个方法作为不安全代码
using System;
namespace ConsoleApp
{
class Program
{
static unsafe void Main(string[] args)
{
}
}
}
// 声明方法的一部分作为不安全代码
using System;
namespace ConsoleApp
{
class Program
{
public static void Main()
{
unsafe
{
int i = 20;
int* p = &i;
Console.WriteLine("Address is: {0} ", (int)p);
}
Console.ReadKey();
}
}
}
C#在有限的范围内支持指针。C#的指针是一个持有另一类型内存地址的变量。在C#中,指针只能被声明为持有值类型和数组的内存地址。与引用类型不同,指针类型不被默认的垃圾收集机制所跟踪。出于同样的原因,指针不允许指向引用类型,甚至不允许指向包含引用类型的结构类型。
定义指针
| 实例 | 描述 |
|---|---|
int* p | p 是指向整数的指针。 |
double* p | p 是指向双精度数的指针。 |
float* p | p 是指向浮点数的指针。 |
int** p | p 是指向整数的指针的指针。 |
int*[] p | p 是指向整数的指针的一维数组。 |
char* p | p 是指向字符的指针。 |
void* p | p 是指向未知类型的指针。 |
声明多个指针的写法如下:
int* p1, p2, p3;
指针操作符
| 操作符 | 说明 |
|---|---|
| * | 取值运算符 |
| & | 取址运算符 |
| -> | 通过指针处理结构体中的数据(获取或赋值) |
| ++与– | 指针增、减操作 |
| fixed | 用户暂时固定托管代码中引用类型的位置。 |
| Stackallc | 分配内存 |
unsafe修饰符时指针的使用
// 使用了 **unsafe** 修饰符时指针的使用
using System;
namespace ConsoleApp
{
class Program
{
static unsafe void Main(string[] args)
{
int var = 20;
int* p = &var;
Console.WriteLine("数据是: {0} ", var);
Console.WriteLine(数据存放的地址是: {0}", (int)p);
Console.ReadKey();
}
}
}
使用指针检索数据值
// 使用指针检索数据值
// 不用声明整个方法作为不安全代码,只声明方法的一部分作为不安全代码。
namespace UnsafeCodeApplication
{
class Program
{
public static void Main()
{
unsafe
{
int var = 20;
int* p = &var;
Console.WriteLine("数据是: {0} ", var);
Console.WriteLine("数据是: {0} ", p->ToString());
Console.WriteLine("数据存放的地址是: {0} ", (int)p);
}
}
}
}
传递指针作为方法的参数
class TestPointer
{
public unsafe void swap(int* p, int* q)
{
int temp = *p;
*p = *q;
*q = temp;
}
public unsafe static void Main()
{
TestPointer p = new TestPointer();
int var1 = 10;
int var2 = 20;
int* x = &var1;
int* y = &var2;
Console.WriteLine("转换前: var1:{0}, var2: {1}", var1, var2);
p.swap(x, y);
Console.WriteLine("转换后: var1:{0}, var2: {1}", var1, var2);
Console.ReadKey();
}
}
固定Fixed
在垃圾收集过程中,C#垃圾收集器可以随意移动内存中的对象。C#提供了一个特殊的关键字fixed来告诉垃圾收集器不要移动一个对象。
在句子块前输入关键字fixed,将会告知CLR块内的目标不能重定位,这样CLR就不会重定位指针指向的数据存储方位。因而在C#固定指针时,运用关键字fixed将能阻挠程序运行时无效指针的发生。
class TestPointer
{
public unsafe static void Main()
{
int[] list = { 10, 100, 200 };
fixed (int* ptr = list)
/* 显示指针中数组地址 */
for (int i = 0; i < 3; i++)
{
Console.WriteLine("Address of list[{0}]={1}", i, (int)(ptr + i));
Console.WriteLine("Value of list[{0}]={1}", i, *(ptr + i));
}
Console.ReadKey();
}
}
常量
常量是固定值,程序执行期间不会改变。常量可以是任何基本数据类型,比如整数常量、浮点常量、字符常量或者字符串常量,还有枚举常量。
// 定义常量
const <数据类型> <常量名称> = 值;
const int i = 10;
封装
封装 被定义为"把一个或多个项目封闭在一个物理的或者逻辑的包中"。在面向对象程序设计方法论中,封装是为了防止对实现细节的访问。
- public:所有对象都可以访问;
- private:对象本身在对象内部可以访问;
- protected:只有该类对象及其子类对象可以访问
- internal:同一个程序集的对象可以访问;
- protected internal:访问限于当前程序集或派生自包含类的类型。
public
所有对象都可以访问
using System;
namespace packaging
{
class APP1
{
public int lenght = 10;
}
class APP2
{
public static void Main (String[] args)
{
var p = new APP1();
Console.WriteLine(p.lenght);
}
}
}
如果将public改为private或protected则会收到错误消息不可访问,因为它受保护级别限制。
protected
只有在通过派生类类型进行访问时,基类的受保护成员在派生类中才是可访问的。
class Point
{
protected int x;
protected int y;
}
class DerivedPoint : Point
{
static void Main()
{
var dpoint = new DerivedPoint();
var p = new Point();
// p.x = 20;
dpoint.x = 10;
dpoint.y = 15;
Console.WriteLine($"x = {dpoint.x}, y = {dpoint.y}");
}
}
语句 p.x = 20; 生成错误,因为它是在静态方法 Main 中生成的,而不是类 Point 的实例。
internal
只有在同一程序集的文件中,内部类型或成员才可访问
// APP1.cs
using System;
namespace demo1
{
public class APP1
{
internal int i = 30;
}
}
// APP2.cs
using System;
using static demo1.APP1;
namespace demo1
{
internal class APP2
{
static void Main()
{
var P = new demo1.APP1();
Console.WriteLine(P.i);
}
}
}
private
私有访问是允许的最低访问级别。 私有成员只有在声明它们的类和结构体中才是可访问的,如以下示例所示:
class demo
{
private readonly string i = "私有成员";
public string GetData()
{
Console.WriteLine(i);
return i;
}
}
class read
{
static void Main()
{
var p = new demo();
//Console.WriteLine(p.i);
p.GetData();
}
}
语句 Console.WriteLine(p.i); 生成错误不可访问,因为它具有一定的保护级别
小结
先发布一下,还挺长的,明明上学的时候学过,有种死去的记忆在攻击自己的感觉,哈哈哈!只好从头学起了!
本文正在参加「金石计划」