zoukankan      html  css  js  c++  java
  • C#

    1、类型推导

    var age = 18;
    Console.WriteLine(age.GetType().ToString());

    var 关键字还可以配合生成匿名类型,如:

    var log = new {Userid = "100234", OpeType = 3, Time = 1481874394};

     如果有可以将对象转成JSON的方法,就可以非常方便的生成各种动态JSON数据了。

    2、公共基类

    公共基类 object 是 System.Object 的假名,所有类都继承自 System.Object 类,比如所有对象都可以重写 ToString() 方法。 

    3、在字符串前面加上 @ 符号,表示非转义字符串。

    如 string filepath = @"C:Windows est.cs";

    4、switch语句支持将字符串作为测试变量

    5、枚举

    枚举的强大之处是它们在后台会实例化为派生于基类System.Enum的结构,从而可以调用方法执行一些任务。

     1 using System;
     2 
     3 namespace Learn
     4 {
     5     public enum TimeOfDay
     6     {
     7         Morning = 0,
     8         Afternoon = 1,
     9         Evening = 2,
    10     }
    11         
    12     class MainClass
    13     {
    14         public static void Main (string[] args)
    15         {
    16             var name = @"	Luna";
    17             Console.WriteLine ("name: " + name + "	type: " + name.GetType ().ToString ()); 
    18 
    19             var log = new {Userid = "100023", OpeType = 3, Time = 13934342389};
    20             Console.WriteLine (log.GetType ().ToString ());
    21 
    22             var platform = "iOS";
    23             switch (platform) {
    24             case "ios":
    25                 Console.WriteLine ("iOS");
    26                 break;
    27             case "android":
    28                 Console.WriteLine ("Android");
    29                 break;
    30             default:
    31                 Console.WriteLine ("other");
    32                 break;
    33             }
    34 
    35             TimeOfDay time = TimeOfDay.Afternoon;
    36             //note: `time` 输出的是枚举名,而不是枚举值
    37             Console.WriteLine (time);
    38             Console.WriteLine (time.ToString ()); //同 `time`
    39             //枚举项可以看成 INT 的装箱类型,所以使用强转拆箱操作即可获取枚举值
    40             Console.WriteLine ((int)time);
    41             //通过给定字符串获取枚举对象
    42             var t = "1morning";
    43             try {
    44                 TimeOfDay time2 = (TimeOfDay)Enum.Parse (typeof(TimeOfDay), t, true);
    45                 Console.WriteLine (time2);
    46             } catch (Exception e) {
    47                 Console.WriteLine (e.ToString ());
    48             }
    49         }
    50 
    51         //override
    52         public override string ToString ()
    53         {
    54             return string.Format ("[MainClass]");
    55         }
    56     }
    57 }

    6、编译

    使用 /target 选项(简写成 /t)来指定要创建的文件类型,如

    /t:exe    控制台应用程序(默认)
    /t:library  带有清单的类库
    /t:module  没有清单的组件
    /t:winexe  Windows应用程序(没有控制台窗口)

    还有 /out 选项用于指定输出文件名

    /reference  选项(简写成 /r)指定链接库

    7、预处理器

    #define 和 #undef  定义某个变量/取消定义某个变量

    #if、#elif、#else 和 #endif  常常和 #define/#undef 指令配合使用,如果某个变量被定义,则执行某逻辑,最常用于跨平台代码、debug/release代码区分。

    #warning 和 #error 指令用于让编译器产生警告和错误,常配合上面的指令使用,用于判定是否错误设定了 #define 指令。

    #pragma 忽略或还原某类编译警告,比如使用了第三方库报了警告,又不方便去修改它,作为强迫症患者可能就需要使用这个指令了。

     1 using System;
     2 namespace Learn
     3 {
     4     class MainClass
     5     {
     6         public static void Main (string[] args)
     7         {
     8             //C#的预定义功能,只支持`是否存在`的定义,而不支持`值判断`的定义
     9             //比如 UNITY 默认根据当前平台,定义了相应的宏
    10             string platform = "";
    11             #if UNITY_EDITOR_WIN
    12                 platform = "UNITY_EDITOR_WIN";
    13             #elif UNITY_EDITOR_OSX
    14                 platform = "UNITY_EDITOR_OSX";
    15             #elif UNITY_IOS
    16                 platform = "UNITY_IOS";
    17             #elif UNITY_ANDROID
    18                 platform = "UNITY_ANDROID";
    19             #else
    20                 #error "platform is undef!"
    21             #endif
    22             Console.WriteLine (platform);
    23         }
    24     }
    25 }

    8、参数类型

    默认引用类型都是通过引用传递,值类型都是通过值传递。如果希望将值类型通过引用传递,可以使用 ref 参数。不同于 C/C++,C#中的 ref 参数必须在使用前赋值,所以也就不方便像C/C++那样通过引用类型参数作为输出参数了,C#中的输出参数使用 out 参数,out 参数也是引用传递,机制跟 ref 参数相同,只是在使用前不需要初始化。

    将引用参数和输出参数按功能性用不同的关键字分离开来,我觉得还是不错的。

    注意,C# 调用有 ref 参数或 out参数的函数时,要显式代入 ref 关键字和 out 关键字。

    调用函数时,默认按参数顺序依次代入参数,但也可以根据参数名显式代入参数,如此则不需要按顺序代入。

    可选参数必须放在参数列表的最后,而且必须有默认值。

    public void Calc(ref int num,out bool b) {
        num *= 100;
        b = true;
    }
        
    public static void Main (string[] args)
    {
        int num = 100;
        bool b;
        var obj = new MainClass ();
        obj.Calc (ref num,out b);
        Console.WriteLine ("num: " + num + "	b: " + b);
    }

    9、字段与属性

    字段一般为小写(很多人习惯为字段添加下划线前缀)且为私有,而属性则是用来访问/修改字段的访问器,可以为访问器设置不同的访问修饰符,来控制访问权限。

    可以书写自动实现的属性,这样就不需要声明字段,编译器会自动创建它。如 public int Age {get; set;}

    readonly字段 和 const字段: 

    readonly 比 const 要灵活得多,const 用于修饰成员字段时,需要显示声明为 static ,且在声明时必须指定初始值。而 readonly 字段可以作为普通成员字段(意即每一个实例都可以有一个不同的常量),也可以作为static成员字段,它可以在构造函数里进行赋值,而不能在其它地方赋值。

     1 using System;
     2 namespace Learn
     3 {
     4     class User 
     5     {
     6         private int _Gold;
     7         public int Gold 
     8         { 
     9             get
    10             { 
    11                 return this._Gold;
    12             } 
    13             set 
    14             {
    15                 if (value < 0) 
    16                 {
    17                     this._Gold = 0;
    18                 }
    19             }
    20         }
    21     }
    22     
    23     class MainClass
    24     {
    25         public static void Main (string[] args)
    26         {
    27             User user = new User ();
    28             user.Gold = 100;
    29             user.Gold -= 200;
    30             Console.WriteLine (user.Gold);    //print `0`
    31         }
    32     }
    33 }

    10、struct

    C#也同样支持 struct,与 class 不同的是, C# 的 struct 是值类型,不支持继承,而且其默认构造函数不允许替换(即不允许重写无参构造函数),不能在类中直接初始化成员(默认都初始化成初值,如数值全部初始化为0),必须先为struct成员赋值后才可使用,分配于栈中。

    所以如果是 User user; 这样的代码,如果User 是一个 class,将会编译出错(未初始化的引用),而如果是 struct,则不会,因为栈中变量的声明实际上就已经在栈中分配空间了。

    因为结构是分配于栈中,所以生成和删除的速度都很快,但又因为结构是值类型,所以作为参数传递效率又很低,所以何时使用结构要根据实际情况而定。

    struct 派生自 System.ValueType,而 System.ValueType 又派生自 System.Object.

    11、强引用和弱引用

    一般声明一个对象等操作,都是强引用,这样垃圾回收器就不会回归该资源,但有时由于对象特别大,并不希望总是占用资源,可以使用弱引用,弱引用使用 WeakReference 类创建,因为弱引用对象随时会被回收,所以在使用之前,必须先确定该对象仍然存在,如:

    WeakReference userRef = new WeakReference(new User());
    GC.Collect();  //手动调用垃圾回收,但不保证立即回收弱指针
    if(userRef.IsAlive)
    {
      User user = userRef.Target as User;
    }

      

    12、部分类

    C#允许将一个类的实现拆分多个文件中,其好处是一方面可以将一个庞大的类按功能拆分,另一方面,对于扩展一个类功能也非常方便(尤其是对于扩展第三方库的类)。

    13、扩展方法

    扩展方法是静态方法,尤其对于不能修改源代码的第三方库,可以通过此方式来扩展功能。在一个静态类中,用一个静态方法来实现扩展方法,扩展方法的第一个参数是要扩展的类型,且需要使用 this 关键字修饰,扩展方法内部可以访问所扩展类型的所有公有方法和属性。在调用扩展方法时,跟调用普通的成员方法一样,都是使用实例去调用,如:

    public static class MoneyExtension
    {
      public static void AddToAmount(this Money money, int add)
      {
        money.Amount += add;
      }
    }

    14、继承

      C#不允许多重实现继承(C++支持多重实现继承,有其优点,但缺点也是显而易见的,非常难以理解和调试),但支持多重接口继承。

      虚方法和虚属性,只有声明为 virtual 的方法和属性,才可以在派生类中重写,重写时需要使用 override 关键字显式声明(C++没有override,所以当误写了方法签名时,编译器是不会报错,它会以为你只是声明了一个新的方法,而C#则无此问题),如果派生类中实现了一个和基类完全相同签名的方法(没有使用 virtual 和 override),则会隐藏基类的方法,在C#中隐藏一个基类的方法,需要使用 new 关键字显式标明,否则编译器会给出警告。(一切都是为了更明确,减少风险)

      抽象类和抽象函数使用 abstract 关键字修饰,抽象类不能被实例化,抽象函数不能被直接实现,只能在派生类中重写(抽象类其实也是 virtual 的)。

      密封类和密封方法,为了防止类被继承或方法被重写,可以使用 sealed 关键字修饰。密封类一般用于商业原因中,不希望第三方扩展自己的功能而使用。string 类就是一个密封类,了解即可。

      在调用派生类构造函数时,总是先根据继承树检查基类,先调用基类的构造函数,所以继承树中的构造函数调用,是从System.Object类开始依次调用的。派生类构造函数默认需要调用基类的默认构造函数,如果基类没有默认构造函数(设置为private或重载了构造函数),则会编译错误,需要显式的调用基类其它构造函数。(我需要写写demo测试一下) 

      接口可以继承接口。

    15、泛型

      泛型的默认值不能使用 null,因为泛型类型也可以实例化成值类型,而 null 只能表示引用类型。为了解决这个问题需要引入 default 关键字。

    1 public T Pop()
    2 {
    3     T item = default(T);
    4     if (list.Count > 0) {
    5         item = list.First.Value;
    6         list.RemoveFirst ();
    7     }
    8     return item;
    9 }

      如果泛型类需要调用泛型类型中的方法,就必须添加约束,比如要求 T 必须满足什么接口等,泛型约束有6种:

    1 where T : struct    //值类型
    2 where T : class    //引用类型
    3 where T : Interface     //实现某个接口
    4 where T : BaseClass    //继承某个基类
    5 where T : new()    //必须有一个默认构造函数
    6 where T : T2    //T 派生自泛型类型T2,也称为裸类型约束

      泛型类也是一个类,可以实现一个接口或继承另一个类,比如常见的实现 IEnumerable<T> 接口

      泛型类也可以声明静态成员,泛型类的静态成员只能在类的一个实例中共享,如:

    public class Test<T> 
    {
        public static int x;
    }
    
    class MainClass
    {
        public static void Main (string[] args)
        {
            Test<int>.x;
            Test<string>.x;
        }
    }

      协变和抗变,貌似在unity中是有问题的。还有泛型结构: Nullable<T> ,暂且略过。

  • 相关阅读:
    JQ 放大镜
    Jquery.tmpl
    Jquery Live方法
    Bootstrap之底层媒体查询
    Bootstrap 字体与图标
    工具提示
    模态框
    BootStrap格栅系统
    Tab选项卡
    弹出框
  • 原文地址:https://www.cnblogs.com/tianyajuanke/p/6186624.html
Copyright © 2011-2022 走看看