在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
C#与C++比较概况:
C#具有如下一些特性: 1. C#是强类型语言,所有变量都必须清楚标记为某个特定数据类型 2. C#中基本类型、枚举、结构体为值类型,数组、类(string、object及自定义类)、接口为引用类型 3. 值类型创建在栈上,引用类型创建在托管堆上(由GC来自动管理) 4. 局部变量、out参数变量要在显示初始化赋值后才能访问 5. 成员变量、static成员变量,在没有被显示初始化时,都会被编译器在构造函数或静态构造函数中默认赋初始值,其规则为:值类型为0或false,引用类型为null 详见:en 6. 大小写敏感:关键字、宏、变量名、函数名、命名空间名 7. 没有全局变量、没有全局静态变量、没有局部静态变量、没有全局函数,所有东西必须写入结构体或类中 8. 所有类型(含值类型)直接或间接都从object类继承 9. 类单根继承,接口多继承 10. 支持运算符重载(与c++相比,运算符重载函数为public static的) 11. 变量、属性和函数默认为private类型 12. 将程序集添加到工程后,无需显示包含其文件或导入包,带上完整的命名空间即可使用其定义的类型 13. 有构造函数和静态构造函数,没有析构函数,通过引用计数机制进行垃圾回收 14. 成员函数和成员属性默认不是virtual的
值类型与引用类型的补充说明: 值类型和引用类型都继承自System.Object类,不同的是,值类型从System.Object的子类System.ValueType继承。 System.ValueType本身是一个类类型,而不是值类型;System.ValueType没有添加任何成员,但覆盖了所继承的一些方法,使其更适合于值类型。 如:System.ValueType重写了Equals()方法,从而对值类型按照实例的值来比较,而不是引用地址来比较。
C#预定义基本类型
一些用法: int a = 2; int a = new int(); // 等价于int a = 0; int a = default (int); // 等价于int a = 0;
C#预定义引用类型
一些用法: object o = null; object o = default(object);
基本类型与string间转换 1. 基本类型 --> string,可以调用对应CTS类型中的ToString方法 2. string --> 基本类型,可以调用对应CTS类型中的Parse和TryParse方法 注:如果string不满足转换要求,Parse方法将会引发一个异常,TryParse方法不会引发异常,它会返回fasle。
各类型之间转换 2. 使用Convert类进行基本类型、string、DateTime结构体之间的转换 int i = 10; float f = i;//f=10 byte b = (byte)i;//b=10 string s1 = "123.5"; f = Convert.ToSingle(s1); //f=123.5 string s2 = "123abc"; i = Convert.ToInt32(s2); //抛出System.FormatException异常 3. 子类对象可以隐式转换为父类对象,父类对象必须显示转换为子类对象(若类型不匹配,则抛出'System.InvalidCastException异常) 4. 值类型可以隐式转换为object类型(装箱),object类型必须显示转换为值类型(类型必须强匹配,int装箱的object只能拆箱成int,不能是long、float等;若类型不匹配,则抛出'System.InvalidCastException异常)
checked / unchecked 1. 编译器默认是关闭溢出检查的,建议在测试时开启该checked编译选项 2. checked/unchecked开启/关闭溢出检查 注:若开启了checked溢出检查,运行时发生溢出会抛出OverflowException异常 byte b1 = 255; int i1 = int.MinValue; try { checked { try { unchecked { b1++; // 不对b1进行溢出检查 } } catch (OverflowException) { Console.WriteLine("b1 OverflowException."); // 不会打印该log } CheckFunc(); // 不会对调用的函数进行溢出检查 i1--; // 检查发现i1溢出,抛出异常 } } catch (OverflowException) { Console.WriteLine("i1 OverflowException."); // 会打印该log } 注:checked或者unchecked只影响其包围的语句,不会影响到包围的语句内调用函数
is、as运算符 int i1 = 10; string s1 = "Hello"; object o1 = "Hi"; object o2 = 100; if (i1 is object) // true { Console.WriteLine("i1 is object"); } if (s1 is object) // true { Console.WriteLine("s1 is object"); } if (o2 is string) // false { Console.WriteLine("o2 is string"); } object i2 = i1 as object; // i1=10被装箱 string s2 = o1 as string; // s2="Hi" string s3 = o2 as string; // s3=null
sizeof 1.只能用于值类型(基本类型、枚举和只包含值类型的结构体) 2.只包含值类型的结构体需要在unsafe块中使用 struct Color { public float R; public float G; public float B; public float A; } int i1 = 10; object i2 = 20; string s1 = "Hi"; Console.WriteLine(sizeof(int)); //4 //Console.WriteLine(sizeof(i1)); //编译不过 Console.WriteLine(sizeof(double)); //8 Console.WriteLine(sizeof(TimeOfDay));//TimeOfDay枚举类型的size为4 Console.WriteLine(System.Runtime.InteropServices.Marshal.SizeOf(i1)); //4 Console.WriteLine(System.Runtime.InteropServices.Marshal.SizeOf(i2)); //4 //Console.WriteLine(System.Runtime.InteropServices.Marshal.SizeOf(int));//编译不过 unsafe // 编译设置中需要勾选Allow unsafe code { Console.WriteLine(sizeof(Color)); // 16 } Console.WriteLine(System.Runtime.InteropServices.Marshal.SizeOf(s1)); //抛异常System.ArgumentException
typeof namespace ConsoleApplication1 { enum TimeOfDay { Moring = -10, Afternoon = -11, Evenving } struct Color { public float R; public float G; public float B; public float A; } } Type t1 = typeof(TimeOfDay); Type t2 = typeof(Color); Console.WriteLine(t1);//ConsoleApplication1.TimeOfDay Console.WriteLine(t2);//ConsoleApplication1.Color Console.WriteLine(typeof(int));//System.Int32 Console.WriteLine(typeof(string));//System.String
可空类型? 派生于结构体Nullable<T> 1. 可空类型与其他可空类型之间的转换,遵循非可空类型的转换规则:如:int?可隐式转换为long?、float?、double?和decimal? 2. 非可空类型与其他可空类型之间的转换,遵循非可空类型的转换规则:如:int可隐式转换为long?、float?、double?和decimal? 3. 可空类型必须显示地转换为非可空类型(若可空类型为null,转换时抛System.InvalidOperationException异常) 4. 可空类型与一元或二元运算符一起使用时,如果其中一个操作数或两个操作数都是null,其结果就是null int? a = null; int? b = a + 1;//b=null int? c = a * 2;//c=null int? d = 3;//d=3 //比较的2个数中只要有一个为空类型则为false if (a >= d) { Console.WriteLine("a>=d"); } else if (a < d) { Console.WriteLine("a<d"); } else { Console.WriteLine("Oh, My God!");//该行被打印 }
空合并运算符?? 1. 空合并运算符:若第一个操作数不是null,表达式为第一个操作数的值;若第一个操作数为null,则表达式为第二个操作数的值 int? a = null; int? b = 3;//b=3 int c = a ?? 4;//a为空类型,则把??后面的数4赋值给c int d = b ?? 5;//b不为空类型,则把b赋值给d
空条件运算符?.和?[] 【c#6.0】 1. 实例在访问成员或数组访问元素前自动判空,不用显示添加手动判空代码,让程序更优雅 int? len = customers?.Length; //null if customers is null 等价于int? len = (customers==null?null:customers.Length) Customer first = customers?[0]; // // null if customers or customers[0] is null 等价于Customer first = (customers==null?null:(customers.Length==0?null:customers[0])) int? count = customers?[0]?.Orders?.Count(); // 等价于int? count = (customers==null?null:(customers.Length==0?null:(customers[0]==null?null:(customers[0].Orders==null?null:customers[0].Orders.Count))))
条件语句 1. swith case可以把字符串当作测试变量 switch (country) { case "China": break; case "America": break; default: break; }
循环语句 1. foreach循环 foreach (int n in arrayOfInts) { Console.WriteLine(n); }
命名空间别名 除了C#与C++比较概况中提到的命名空间的用法外,C#还允许使用别名来简化类型对命名空间的使用(注:通过::符号来使用) using System; using InterSrv = System.Runtime.InteropServices; byte a = 3; int nLen = InterSrv::Marshal.SizeOf(a.GetType()); Console.WriteLine("Type is {0}, Length is {1}.", a.GetType().ToString(), nLen); // Type is System.Byte, Length is 1.
函数参数传递 【ref out】 int a1 = 1, b1 = 2; Func(a1, b1);//函数返回后,a1=1 b1=2 int a2 = 1, b2 = 2; FuncRef(ref a2, ref b2);//函数返回后,a2=2 b2=1 int a3 = 1;//由于out参数不会使用该初值,因此a3可以不用赋初值 FuncOut(out a3);//函数返回后,a3=5 CA oa1 = null; Func2(oa1);//函数返回后,oa1=null CA oa2 = null; FuncRef2(ref oa2);//函数返回后,oa2不为null,oa2.Id=100 CA oa3 = new CA();//由于out参数不会使用该初值,因此oa3可以不用赋初值 FuncOut2(out oa3);//函数返回后,oa3=null void Func(int a, int b) { int c = a; a = b; b = c; } void FuncRef(ref int a, ref int b) { int c = a; a = b; b = c; } void FuncOut(out int a) { //int b = a; //在函数中未给out参数变量a赋值之前,不能访问a a = 5;//在函数返回之前必须要对a进行赋值 } void Func2(CA o) { o = new CA(); o.Id = 100; } void FuncRef2(ref CA o) { o = new CA(); o.Id = 100; } void FuncOut2(out CA o) { //bool b = (o != null);//在函数中未给out参数变量o赋值之前,不能访问o o = null;//在函数返回之前必须要对o进行赋值 }
命名参数 【c#4.0】 string s = GetFullName(LastName: "Li", FirstName: "Lei"); string GetFullName(string FirstName, string LastName) { return FirstName + " " + LastName; }
缺省参数 【c#4.0】 string GetFullName(string FirstName, string LastName="Chen") { return FirstName + " " + LastName; }
数组型参数 params会把传入各个参数存放在一个object数组中 1.params参数必须放在最后 public static void Test(int n, params object[] list) { Console.WriteLine(n); for (int i = 0; i < list.Length; i++) { Console.WriteLine(list[i]); } } Test(100, false, 3, "Test");//打印出:100 False 3 Test
类型推断 【c#3.0】 1.推断出了类型后,就不能改变类型了 2.类型确定后,就遵循强类型化规则 var name = "Jim Green"; var age = 20; var height = 1.825f; var sex = true; //var weight; 编译不过,必须在声明时初始化 //weight = 60.5; Console.WriteLine("name's type is {0}", name.GetType());//name's type is System.String Console.WriteLine("age's type is {0}", age.GetType());//age's type is System.Int32 Console.WriteLine("height's type is {0}", height.GetType());//height's type is System.Single Console.WriteLine("sex's type is {0}", sex.GetType());//sex's type is System.Boolean Object o = new Object(); var o1 = new Object(); var o2 = o; //var friend = null;编译不过,不能为空
匿名类型 var与关键字new一起使用可以创建匿名类型;匿名类型只是一个从Object派生没有名称的类,该类的定义从初始化器中推断 匿名类型名有编译器按照一定规则产生,我们不应该使用任何该类型的反射 //生成一个包含string FirstName, string MiddleName, string LastName属性的类型,并用该类型初始化出个名为captain的实例 var captain = new { FirstName = "James", MiddleName = "T", LastName = "Kirk" }; //生成一个包含string Location, int Area, double Population属性的类型,并用该类型初始化出个名为china的实例 var china = new { Location = "Asia", Area = 960, Population = 1.3 }; // doctor与captain的变量名、类型、顺序完全一致,为同一匿名类型;因此,不会创建新的类型,而是使用captain类型来初始化captain var doctor = new { FirstName = "Leonard", MiddleName = "T", LastName = "McCoy" }; Console.WriteLine("captain's type is {0}", captain.GetType());//captain's type is <>f__AnonymousType0`3[System.String,System.String,System.String] Console.WriteLine("china's type is {0}", china.GetType());//china's type is <>f__AnonymousType1`3[System.String,System.Int32,System.Double] Console.WriteLine("doctor's type is {0}", doctor.GetType());//doctor's type is <>f__AnonymousType0`3[System.String,System.String,System.String]
格式化输出到控制台 格式符形如:{D[,D[:C[D]]]} -- D、D、D表示数字,C表示字母 D:后续参数序号,从0开始 D:占位数目(占位数少于变量自身数目时,不产生多余占位;货币符号算1个占位):为正数,表示右对齐;为负数,表示左对齐 D:整型数时,为整个数的位数,不够时左边补0;浮点数时,为小数点后的位数 C:① D -- 十进制格式 ② E、e -- 科学计数法,默认小数点后的位数为6 ③ F -- 浮点数格式 ④ G -- 普通格式 ⑤ N -- 数字格式,逗号表示千位符 ⑥ P -- 百分数格式 ⑦ X -- 十六进制格式 ⑧ C -- 本地货币格式 中国区为:¥ int i = 262, j = 350; Console.WriteLine("{0}#{1}", i, j);//262#350 Console.WriteLine("{0,4}#{1,5}", i, j);// 262# 350 Console.WriteLine("{0,-4}#{1}", i, j);//262 #350 Console.WriteLine("{0,6:D5}#{1}", i, j);// 00262#350 int m = 26252, n = 350390; Console.WriteLine("{0,0:D}#{1,0:F}", m, n);//26252#350390.00 Console.WriteLine("{0,0:G}#{1,0:N}", m, n);//26252#350,390.00 Console.WriteLine("{0,0:E}#{1,0:e}", m, n);//2.625200E+004#3.503900e+005 Console.WriteLine("{0,0:X}#{1,0:P}", m, n);//668C#35,039,000.00% float f = 35.0f, g = -20.388f; Console.WriteLine("{0,7:F3}#{1,0:E2}", f, g);// 35.000#-2.04E+001 Console.WriteLine("{0,4:C2}#{1,0:e3}", f, g);//¥35.00#-2.039e+001 Console.WriteLine("{0,6:C1}#{1,0:P3}", f, g);// ¥35.0#-2,038.800%
字符串(16位unicode) String处理不变的字符串,,不可被继承(sealed),任何对String的改变都会引发新的String对象的生成 string s0 = "你好"; int ns0Len = s0.Length; // ns0Len = 2 char[] sz = new char[] { 'h', 'e', 'l', 'l', 'o' }; string s1 = "hello"; // 静态创建字符串对象 string s2 = new string(sz); |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论