[リーディングノート] C#スタディノート7:C#4.0のマイナーな変更-オプションのパラメーター、一般的な変動性


[リーディングノート] C#スタディノート7:C#4.0のマイナーな変更-オプションのパラメーター、一般的な変動性

序文

この本の最後のポイントでもあるC#4.0での変更点のいくつかを要約してみましょう。この部分はようやく更新されます。同時に、2回目に読んだときに、さまざまなメリットがあると感じています。今日はウーハンでとても幸せです。雪が降っています。明日の土曜日、すべてがとても美しくなります。ハハハ。
メインコンテンツには、オプションのパラメータと名前付き引数、ジェネリックの可変性、動的タイプが含まれます。

1.オプションのパラメーターと名前付きの実際のパラメーター
1.1オプションのパラメーター
オプションのパラメーターと名前付きの実際のパラメーターは、一緒に使用されることが多いため、友だちの良いペアのようです。オプションのパラメーターは、「オプション」、つまりメソッドを呼び出すときに焦点を当てます
パラメータは、実際のパラメータを明示的に指定することも、指定しないこともできます。次のコード:

 

コードをコピーする

 1クラスプログラム2 {3 static void Main()4 {5 TestMethod(1、2、 "WangMeng"); 6 TestMethod(2、3); 7 Console.ReadKey(); 8} 9 10 //带有可選択参数的方法11staticvoid TestMethod(int x、int y = 10、string name = "BarryWang")12 {13 Console.Write( "x = {0} y =(1 )name = {2}; "、x、y、name); 14} 15}

コードをコピーする

 

印刷結果は次のとおりです。

 


不思議な感覚はありますか?これは、特にシステムのポストメンテナンスにオプションのパラメーターが役立つ場所です。次の例のように、実際のプロジェクトでもそのような使用法を使用しました。

作成したシステムでユーザーを切り替えるには、SwitchUser(現在のユーザーを除外せずに新しいユーザーログインを追加する)とTransferUser(現在のユーザーをログアウトしてから新しいユーザーにログインする)の2つの方法があります
が、システムはログインしたユーザーの数を実行します。制限事項、およびSwitchUserとTransferUserはどちらも同じ制限付きCheckメソッドを使用し、Userの2つの操作メソッドが異なるため、TransferUserで問題が発生します。
ここでの解決策は、同じCheckメソッドを使用することですが、このCheckメソッドを指定します。実行する操作を決定するための新しいオプションのパラメーターが追加され、さまざまな操作に従って対応する変更が行われます。

オプションパラメータを使用する場合は、次の制約に注意する必要があります。
(1)すべてのオプションパラメータは必須パラメータの後に配置する必要があります。
(2)オプションパラメータのデフォルト値は常にオンである必要があります。
(3)パラメータ配列( params修飾子宣言)をオプションパラメータとして使用することはできません
(4)refまたはoutキーワードで識別されるパラメータをオプションパラメータとして設定することはできません

ここを見ると、オプションのパラメータの最大の利点は、後でシステムのメンテナンスを容易にすることであることがわかります。他の利点はまだ発見されていません。

1.2名前付きの実際のパラメーター
システムに2つのオプションのパラメーターがあり、最初のオプションのパラメーターを省略したい場合はどうなりますか?名前付きの実際のパラメーターは、現時点で役立ちます。

コードをコピーする

 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 }

コードをコピーする

打印结果如下图:

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

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.
就我而言

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

好文要顶 关注我 收藏该文  

一枝花算不算浪漫


おすすめ

転載: blog.51cto.com/7592962/2543846