前言html
下面就开始总结C#4.0的一些变化了, 也是这本书中最后的一点内容了, 这一部分终于要更新完了. 同时感受再来读第二遍也有不同的收获. 今天很嗨的是武汉下雪了,明天周六,一切都是这么美好.哈哈哈.
主要内容有: 可选参数和命名实参, 泛型的可变性, 动态类型数组
1,可选参数和命名实参
1.1可选参数
可选参数和命名实参就如同一对好基友, 由于它们常常一块儿使用.
可选参数重在"可选", 即在调用方法时, 该参数能够明确指定实参, 也能够不指定实参.以下代码:微信
1 class Program 2 { 3 static void Main() 4 { 5 TestMethod(1, 2, "WangMeng"); 6 TestMethod(2, 3); 7 Console.ReadKey(); 8 } 9 10 //带有可选参数的方法11 static void TestMethod(int x, int y = 10, string name = "BarryWang")12 {13 Console.Write("x = {0} y = (1) name = {2};", x, y, name);14 }15 }
打印结果以下图:框架
是否是有一种很神奇的感受? 这就是可选参数的好用之处, 特别是对于一个系统的后期维护很好使用, 在真实的项目中我也使用过这样的用法, 以下例:
ide
在咱们作的系统中切换User有SwitchUser(不lougout当前user,而后添加新的user登录)和TransferUser(logout当前user,而后登录新的user)两种方式
可是系统又会进行对登录的user数量进行限制, 而SwitchUser和TransferUser使用的都是同一个限定Check方法,而两种对User的操做方式不一样,因此致使TransferUser会出现问题.
这里的解决方案就是仍然使用同一个Check方法,可是给这个Check方法新添加一个可选参数来判断究竟是执行的哪一个操做, 而后根据不一样的操做去作相应的修改.post
在使用可选参数时, 须要注意一下几个约束条件:
(1)全部可选参数必须位于必选参数以后.
(2)可选参数的默认值必须为常亮.
(3)参数数组(有params修饰符声明)不能作为可选参数
(4)用ref或out关键字标识的参数不能被设置为可选参数学习
看到这里咱们就能够发现可选参数的最大的优势就是便于系统后期的维护. 其余的优势还有待发现.url
1.2命名实参
若是一个系统中有两个可选参数, 而咱们想省略掉第一个可选参数怎么办呢? 命名实参这个时候就能够帮助咱们了.spa
1 class Program 2 { 3 static void Main() 4 { 5 //省略name参数 6 TestMethod(2, 14); 7 //省略y参数和name参数 8 TestMethod(2); 9 //为不分实参指定名称, 经过使用命名实参, 只省略y参数10 TestMethod(2, name : "WangMeng");11 //为全部实参指定名称12 TestMethod(x: 2, y: 20, name: "Hello");13 Console.ReadKey();14 }15 16 //带有两个可选参数的方法17 static void TestMethod(int x, int y = 10, string name = "BarryWang")18 {19 Console.WriteLine("x = {0}, y = {1}, name = {2}", x, y, name);20 }21 }
打印结果以下图:code
有了命名实参, 可选参数的变得更增强大了是否是? 哈哈, 确实是这样.
2,泛型的可变性
在C#2.0 中, 泛型并不具有可变性, 这种是指斜变性和逆变性. 而在C#4.0中引入了泛型的协变性和逆变性.
2.1协变性
协变性指的是泛型类型参数能够从一个派生类隐式转化为基类. 你们能够这样记忆: 协变性即和谐(与"协"同音)的变化,
从派生类转换为基类, 就如同所子女长的像父母同样, 听起来很是和谐. 这样就很容易记住协变了.
C#4.0引入out关键字来标记泛型参数, 以示其支持协变性. 为了更好的进行说明, 下面用.Net类苦中的IEnumerable<out T>接口为例作演示:
1 class Program 2 { 3 static void Main() 4 { 5 //初始化泛型实例 6 List<object> listObject = new List<object>(); 7 List<string> listStrs = new List<string>(); 8 9 listObject.AddRange(listStrs);//成功10 listStrs.AddRange(listObject);//失败11 }12 }
在以上代码中, AddRange方法接收的参数类型为IEnumerable<T>, 该接口的定义为IEnumerable<out T>, 由于其泛型参数有out关键字标识,
因此IEnumerable<T>泛型的类型参数T支持协变性, 则可将List<string>转化为IEnumerable<string>(这是被继承的协变性支持的. 由于List<T>实现了IEnumerable<T>接口).
又由于类型参数支持协变性, 因此能够进一步把IEnumerable<string>转化为IEnumerable<object>
2.2逆变性
逆变性指的是泛型类型参数能够从一个基类隐式地转化为派生类,C#4.0引入in关键字来标记泛型参数, 以示其支持逆变性.
下面使用.Net类库中的接口public interface IComparer<in T>为例进行演示:
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 List<object> listobject = new List<object>(); 6 List<string> liststrs = new List<string>(); 7 // AddRange方法接收的参数类型为IEnumerable<T> collection 8 // 下面的代码是传入的是List<string>类型的参数。 9 // 在MSDN中能够看出这个接口的定义为——IEnumerable<int T>。10 // 因此 IEnumerable<T>泛型类型参数T支持协变性,因此能够11 // 将List<string>转化为IEnumerable<string>(这个是继承的协变性支持的)12 // 又由于这个IEnumerable<in T>接口委托支持协变性,因此能够把IEnumerable<string>转化为——>IEnumerable<object>类型。13 // 因此编译器验证的时候就不会出现类型不能转化的错误了。14 listobject.AddRange(liststrs); //成功15 16 ////liststrs.AddRange(listobject); // 出错17 18 IComparer<object> objComparer = new TestComparer();19 IComparer<string> objComparer2 = new TestComparer();20 21 // List<string>类型的 liststrs变量的sort方法接收的是IComparer<string>类型的参数22 // 然而下面代码传入的是 IComparer<object>这个类型的参数,要编译成功的话,必须可以转化为IComparer<string>这个类型23 // 正是由于IComparer<in T>泛型接口支持逆变,因此支持object转化为string类型24 // 因此下面的这行代码能够编译经过,在.Net 4.0以前的版本确定会编译错误,25 // 你们能够把项目的目标框架改成.Net Framework 3.5或者更加低级的版本26 // 这样下面这行代码就会出现编译错误,由于泛型的协变和逆变是C# 4.0 中新增长的特性,而.Net 4.0对应于C# 4.0。27 liststrs.Sort(objComparer); // 正确28 29 // 出错30 ////listobject.Sort(objComparer2);31 } 32 }33 34 public class TestComparer : IComparer<object>35 {36 public int Compare(object obj1,object obj2)37 {38 return obj1.ToString().CompareTo(obj2.ToString());39 }40 }
在以上代码中, listStrs变量的Sort应接收IComparer<string>类型的参数, 虽然传入的实参是IComparer<objcet>类型,
但由于IComparer<in T>泛型接口支持逆变, 因此可将object转化为string类型.
2.3协变和逆变的注意事项
(1)只有接口和委托才支持协变和逆变, 类或泛型方法的类型参数都不支持协变和逆变
(2)协变和逆变只适用于引用类型, 值类型不支持协变和逆变(例如List<int>没法转化为IEnumerable<objcet>)
(3)必须显式地用in或out来标记类型参数
(4)委托的可变性不要再多播委托中使用
3,动态类型
在C#4.0中, 微软引入了dynamic管家你来定义动态类型. 当咱们使用由dynamic关键字限制的变量时, 编译器并不知道它的类型, 该类型智能在程序运行时才能被肯定.
动态类型的定义为: dynamic i = 5;
动态类型和静态类型到底有什么不一样呢?
1 object obj = 10;2 obj = obj + 10;//出现变异错误3 dynamic i = 10;4 i = i + 10;
解析:
在以上代码中, 第一行的obj为objec他类型, 而编译器却检测出"+"运算符没法应用于object和int类型.
要让编译器经过, 咱们必须使用强制类型转换, 把object转换为int. 即obj = (int)obj + 10;
可是动态类型的引入到底有什么好处呢?
1,能够减小强制类型转换的使用. 由于动态类型是在程序运行时才被肯定, 使用它能够避免代码进行强制类型转换,从而使代码看起来更加简洁.
2,调用Python等动态语言. 动态类型除了能够减小强制类型转换外, 还可让咱们在C#语言中调用Python这样的动态语言.
这里对动态类型介绍的很少, 主要是介绍了一个dynamic关键字, 若是之后用到再来百度就行了.
PS: 想为本身的文字多增长一点内容, 之后每一个帖子后面都会加一些口语小贴士, 这些都是本身平时看过的. 英语真的很重要, 这里不用我多说你们应该都知道的.
口语小贴士:
A fool never learns.
傻瓜永远学不会
A little bird told me.
我据说的
Are you out of your mind?
你疯了吗?
Are you pulling my leg?
你在开我玩笑吗?
As far as I'm concerned.
就我而言