[Reading notes] C# study notes 7: Minor changes in C#4.0-optional parameters, generic variability


[Reading notes] C# study notes 7: Minor changes in C#4.0-optional parameters, generic variability

Preface

Let’s start to summarize some of the changes in C#4.0, which is also the last point in this book. This part is finally about to be updated. At the same time, I feel that there will be different gains when I read it a second time. Today is very happy in Wuhan It’s snowing, tomorrow Saturday, everything will be so beautiful. Hahaha. The
main contents are: optional parameters and named arguments, the variability of generics, dynamic types

1. Optional parameters and named actual parameters
1.1 Optional parameters
and named actual parameters are like a good pair of friends, because they are often used together.
Optional parameters focus on "optional", that is, when calling a method, The parameter can specify the actual parameter explicitly or not. The following code:

 

Copy code

 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 }

Copy code

 

The print result is as follows:

 


Is there a magical feeling? This is where the optional parameters are useful, especially for the later maintenance of a system. I have also used such usage in real projects, as in the following example:

In the system we made, there are two ways to switch User: SwitchUser (not lougout the current user, then add a new user login) and TransferUser (logout the current user, then log in to the new user),
but the system will perform the number of logged-in users. Limitations, and SwitchUser and TransferUser both use the same limited Check method, and the two operation methods for User are different, so TransferUser will have problems.
The solution here is to still use the same Check method, but give this Check method A new optional parameter is added to determine which operation is performed, and then make corresponding modifications according to different operations.

When using optional parameters, you need to pay attention to the following constraints:
(1) All optional parameters must be located after mandatory parameters.
(2) The default value of optional parameters must be always on.
(3) Parameter array (with The params modifier declaration) cannot be used as an optional parameter
(4) The parameter identified by the ref or out keyword cannot be set as an optional parameter

Seeing here we can find that the biggest advantage of optional parameters is to facilitate the maintenance of the system later. Other advantages have yet to be discovered.

1.2 Named actual parameters
What if there are two optional parameters in a system and we want to omit the first optional parameter? Named actual parameters can help us at this time.

Copy code

 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 }

Copy code

打印结果如下图:

有了命名实参, 可选参数的变得更加强大了是不是? 哈哈, 确实是这样.

2,泛型的可变性
在C#2.0 中, 泛型并不具备可变性, 这种是指斜变性和逆变性. 而在C#4.0中引入了泛型的协变性和逆变性.

2.1协变性
协变性指的是泛型类型参数可以从一个派生类隐式转化为基类. 大家可以这样记忆: 协变性即和谐(与"协"同音)的变化,
从派生类转换为基类, 就如同所子女长的像父母一样, 听起来非常和谐. 这样就很容易记住协变了.
C#4.0引入out关键字来标记泛型参数, 以示其支持协变性. 为了更好的进行说明, 下面用.Net类苦中的IEnumerable<out T>接口为例做演示:

Copy code

 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 }

Copy code

在以上代码中, 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>为例进行演示:

Copy code

 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 }

Copy code


在以上代码中, 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.
就我而言

分类: C#基础系列读书笔记

好文要顶 关注我 收藏该文  

一枝花算不算浪漫


Guess you like

Origin blog.51cto.com/7592962/2543846