C#基础规则和需要注意的语言特性

1.IL语言,CRL管理JIT编译

先编译为IL语言,然后运行时候用CRL虚拟机通过即时编译JIT为机器代码,也就是按需编译然后存储起来只编译一次。
关于IL代码和调试:
用C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\ildasm.exe可以打开exe PE文件,dump出中间代码;至于中间代码的调试,64位机器上用dile_v0_2_13_x86不行,暂时不管需要时候再研究。

2.C#和托管C++

C++在托管代码中受限使用指针,不能使用模板和多继承,而且会编译为IL语言,运行时候才JIT编译,.net下的VB和JS也是这样的机制,但是C++有一个优点就是可以调用非托管的C++,C#要调用底层只能通过COM互操作,C#和C++间通信是否要经过托管C++层?

3.net中的所有托管语言都遵守IL和CTS规范

所有.net中语言都要支持IL特性,也就是值和引用的差别,强类型特征,面向对象接口,单继承,异常处理和支持属性。

4.类和结构体成员会初始化,局部变量不会初始化

C#所有功能都由.net提供, 类字段变量和结构体变量会初始化为0,局部变量不会初始化且不初始化调用会出错,不存在全局变量因为都在类中,刚好和CC++相反;

5.C#中的var类型初始化了以后就不能改变类型了

但变量作用域和C++一样;但C#中变量用var声明然后初始化那么会推断出具体类型且推断出来后类型不能改变。

6.常量必须声明时候初始化,不能用变量给它赋值,不能static修饰

常量必须声明时候初始化,不能用变量对其赋值,不能用static修饰因为它就是static的。

7.数据类型分为值类型和引用类型,结构体是值类型,类对象是引用类型对象间赋值都是浅拷贝

数据类型分为值类型和引用类型。类对象需要new赋值后才是有托管堆对象的引用类型对象没有引用赋值为null,对象间赋值都是浅拷贝。
基础类型是.net结构体可以有成员函数,枚举类型是值类型,自定义结构体是值类型。
字符串,数组,decimal类型,自定义类是引用类型。

类型转换:
// 强转类型
public int CompareTo(Object obj)
{
    Person other = obj as Person;
}

8.byte类型和decimal类型

byte类型是无符合的因为unicode编码 sbyte是有符合的,其它都是uint ulong ushort。
decimal财务科学计算专用是128位的浮点数,不是基础类型而是一个引用类型会有点性能损失,后缀可以用M表示。布尔类型只有true false表示不能用01。字符类型是char是16位的处理unicode编码,可以用'A'赋值,也可以'\n'赋值,(char)65,'\u0041' unicode '\x0041' 十六进制来表示。
using System;
  
namespace Wrox
{
  public class Program
  {
    static void Main(string[] args)
    {
      var name = "Bugs Bunny";
      var age = 25;
      var isRabbit = true;
  
      Type nameType = name.GetType();
      Type ageType = age.GetType();
      Type isRabbitType = isRabbit.GetType();
      Type money = typeof(decimal);
  
      Console.WriteLine("name is type " + nameType.ToString());
      Console.WriteLine("age is type " + ageType.ToString());
      Console.WriteLine("isRabbit is type " + isRabbitType.ToString());
      Console.WriteLine( "money type is:" + money.ToString() );
      Console.ReadLine();
    }
  }
}


9.string类型是常量引用类型,如果字符串改变了那么会重新生成一份堆拷贝

自带引用类型包括object类型,string类型,都对应.net相应的基类,同是object是所有类型的基类包括基础值类型,.net编译到自定义类型例如结构体或者类的时候应该都会添加类型的继承。string类型变量都是引用,内容都是常量形式存在; 但是如果字符串改变了,那么string会重新生成一个托管堆对象,地址赋予新的string变量。
using System;

class StringExample
{
   private void DisplayStringEqual(string s1, string s2)
   {
	  if( s1 == s2 )
	  {
		  Console.WriteLine("Str 1 is Equal Str2.");
	  }
	  else
	  {
		   Console.WriteLine("Str 1 is Not Equal Str2.");
	  }
   }
   
   public static int Main()
   {
	  // 没有赋值,字符串是引用类型的,指向同一块内存
	  StringExample obj = new StringExample();
      string s1 = "a string";
      string s2 = s1;
      Console.WriteLine("s1 is: " + s1);
      Console.WriteLine("s2 is: " + s2);
	  obj.DisplayStringEqual(s1, s2);
	 
	  // 如果赋值了那么就是一个新的字符串常量
      s1 = "another string";
      Console.WriteLine("s1 is now: " + s1);
      Console.WriteLine("s2 is now: " + s2);
	  obj.DisplayStringEqual(s1, s2);
	  Console.ReadLine();
      return 0;
   }
}

字符串作为函数参数时候会新增加一个堆对象,不过只是一次,不要紧的。
记得函数中不要不断的生成新的字符串对象,对字符串进行连续的++操作会很影响性能。
字符串判空:
 if (string.IsNullOrEmpty(s)) { }
 if(s != null && s.Length ==0) {} 
性能比 s == ""快很多。
 
字符查找:
  //  Find the first occurrence of the first character
   int  first  =  source.IndexOf(c0,  0 , limit);

字符串拼接:
public string JoinIds(List<User> users)
{
    var ee = users.GetEnumerator();
    StringBuilder sb = new StringBuilder();
    if (ee.MoveNext())
    {
        sb.Append("'");
        sb.Append(ee.Current.Id);
        sb.Append("'");
        while (ee.MoveNext())
        {
            sb.Append(",'");
            sb.Append(ee.Current.Id);
            sb.Append("'");
        }
    }
    return sb.ToString();
}

10.命名规范,以及转义字符\和@

命名区分大小写,命名如果是关键字和其他语言中的标志符那么可以用@表示它是原意不是.net关键字可以调用,不使用匈牙利规则,用类结构常量都大写开头中间小写,变量小写开头中间可大写的命名方式。
字符和字符串的转义字符,可以用\来表示,也可以一整句用@符号表示全部需要转义用原来的字面含义。

11.switch可以用字符串和int作为变量,可以用goto没有break会报错

switch中可以用字符串作为变量不必只是int类型,可以用goto语句,多个case一起执行也是一样的,没有break会编译出错。

12.for each语句

循环多了foreach语句,迭代集合中的每个变量,但是不能改变集合里面的值。

13.枚举值是值类型,枚举对象是引用类型

枚举类型拥有增强代码可读性能力,编译时候会将枚举类型变化为继承自.net enum基类,但是枚举值是值类型,返回对象是引用类型,拥有基类方法可以转换为字符串,也可以从字符串中得到枚举值。

14.命名空间直接用

命名空间一样,嵌套,别名,using,文件结构中没有头文件,全部在类中。都用using system是因为值还是引用类型都要编译时候用.net的基类派生修饰。

15.编译选项

/out 输出文件名,如果不知道从一个源文件名取得。
/t /t:exe控制台程序,/t:winexe windows可执行程序,/t:library库。
 /r 输入时候,参考由给出的汇编文件指定的元数据。
例如:
多个main入口:
csc DoubleMain.cs /main:Wrox.Client

编译DLL库:
csc /t:library MathLibrary.cs

编译其它模块使用库:
csc MathClient.cs /r:MathLibrary.dll

16.格式化输出

格式化输出下标索引,宽度,格式化。

c、C       货币格式。

d、D       十进制格式。

e、E       科学计数(指数)格式。

f、F        固定点格式。

g、G       常规格式。

n、N       数字格式。

r、R        往返格式,确保将已转换成字符串的数字转换回数字时具有与原数字相同的值。

x、X       十六进制格式。

double val = Math.PI; Console.WriteLine(val.ToString()); //displays 3.14159265358979
Console.WriteLine(val.ToString("E"));//displays 3.141593E+000
Console.WriteLine(val.ToString("F3"));//displays 3.142
Single val2=0.123F;Console.WriteLine(val2.ToString("p")); //displays 12.30 %
Console.WriteLine(val2.ToString("p1")); //displays 12.3 %
int val3=65535;
Console.WriteLine(val3.ToString(
"x")); //displays ffff
Console.WriteLine(val3.ToString("X")); //displays FFFF
decimal val4 = 323.42313m;
Console.WriteLine(
"{0,9:f2}",val4); // displays 323.42
//{0,9:f2}表示第0个参数,占9位右对齐,小数点精确两位
Console.WriteLine("{0,-9:f2}", val4); // -9表示占9位,左对齐

17.注释///

除了常规的//和/**/注释,注释可以///指定编译选项生成xml文档。

18.预编译和条件编译以及特性

预编译和条件编译类似cpp,但还可以用特性来控制编译过程。

19.属性和特性类的区别

字段 属性 方法的使用,属性有点类似方法,特性类似编译条件开关宏。


你可能感兴趣的:(C#基础规则和需要注意的语言特性)