CSharpThinking

来源:互联网 发布:知豆电动汽车价格表 编辑:程序博客网 时间:2024/06/04 00:33

实践是检验真理的捷径。

本章主要是理解C#中的协变和逆变的关系,对今后理解泛型会有很大帮助。

1.协变与逆变的概念及代码说明。

 C#1:数组是强类型,强类型不允许内部数据不能相互转换。C#2中引入了对协变与逆变的限制,而C#4中又适当放宽了政策,不过这一切对数组没有任何影响,不过可以用一系列的接口和集合代替数组。

 1             Stephen[] MySelf = new Stephen[1]; 2             MySelf[0] = new Stephen() { Name = "name1", Name2 = "name2" }; 3             StephenBase[] MyBase = MySelf; // 协变 4             Stephen[] OtherMe = (Stephen[])MyBase; // 逆变 5  6 ... 7  8         public class StephenBase 9         {10             public StephenBase() { }11             public string Name { get; set; }12         }13 14         public class Stephen : StephenBase15         {16             public Stephen()17             {18 19             }20 21             public string Name2 { get; set; }22         }

 

委托的协变和逆变

逆变:其中void KeyPressEventHandler(object sender, KeyPressEventArgs e) 继承自 void EventHandler(object sender, EventArgs e)

1 void LogPlainEvent(object sender ,EventArgs e)2 {3      Console.WriteLine("An event occurred!");4 }5 6 Button btn = new Button();7 btn.Click += LogPlainEvent; // 委托逆变8 btn.KeyPress += LogPlainEvent; // 委托逆变

协变:

 1            delegate Stream StreamFactory(); 2  3             StreamFactory sf = GenerateMeoryStream; // 委托协变 4             using (Stream s = sf()) 5             { 6                 int data; 7                 while ((data = s.ReadByte()) != -1) 8                 { 9                     Console.WriteLine(data);10                 }11             } 12 13         static MemoryStream GenerateMeoryStream()14         {15             byte[] buffer = new byte[16];16             for (int i = 0; i < buffer.Length; i++)17             {18                 buffer[i] = (byte)i;19             }20             return new MemoryStream(buffer);21         }

注:协变和逆变是指从基类转换成子类或从子类转换到基类。

 

2.有趣的是:当把一个子类转换成基类,又紧接着转换成了子类,新子类中完全包含旧子类的全部信息,而不仅仅是基类的信息。

1             Stephen[] MySelf = new Stephen[1];2             MySelf[0] = new Stephen() { Name = "name1", Name2 = "name2" }; 3             StephenBase[] MyBase = MySelf; // 协变4             Stephen[] OtherMe = (Stephen[])MyBase; // 逆变5 6             Console.WriteLine("ChildName: " + OtherMe[0].Name2);7             Console.ReadLine();

 接口继承也会在二次复原转换后依然保留原始信息。

 1         public static void InterfaceTest() 2         { 3             HelloStephen stephen = new HelloStephen() 4             { 5                 Email = @"Stephen.Cui@Emerson.com", 6                 Oicq = @"229063661", 7                 IsAlive = true 8             }; 9 10             IHelloStephen istephen = (IHelloStephen)stephen;11             HelloStephen targetStephen = HelloStephen.FindStephen(istephen);12 13             Console.WriteLine("Is Stephen alive ?");14             Console.WriteLine(targetStephen.IsAlive);15             Console.WriteLine("Contact Me ? To : " + targetStephen.Email + " Or QQ : " + targetStephen.Oicq);16         }
 1     /// <summary> 2     /// Descrption: 3     /// IStephen Interface 4     /// </summary> 5     public interface IHelloStephen 6     { 7         string Email { get; set; } 8         string Oicq { get; set; } 9         bool IsAlive { get; set; }10     }11 12     public class HelloStephen : IHelloStephen13     {14         #region IHelloStephen15         string _Email;16         string _Oicq;17         bool _isAlive;18 19         public bool IsAlive20         {21             get { return _isAlive; }22             set { _isAlive = value; }23         }24         public string Email25         {26             get { return _Email; }27             set { _Email = value; }28         }29         public string Oicq30         {31             get { return _Oicq; }32             set { _Oicq = value; }33         }34         #endregion35 36         #region HelloStephen37         public string MyCNBlogs { get; set; }38         #endregion39 40         #region Method41         public static HelloStephen FindStephen(IHelloStephen stephen)42         {43             return (HelloStephen)stephen ?? new HelloStephen() { IsAlive = false };44         }45         #endregion46     }

  

3.方法组转换。

C#1中如果要创建一个委托实例,就必须同时指定委托类型和要采取的操作;C#2提供从方法组(一个方法名,表达式)到一个兼容类型的隐式转换。

1 // C#12 Thread t = new Thread(new ThreadStart(MyMethod));3 4 // C#25 Thread t = new Thread(MyMethod);
View Code

 

4.C#1与C#2中委托协变逆变的不同之处。

  存在不兼容的风险:

1 EventHandler general = new EventHandler(Event);2 KeyPressEventHandler key = new KeyPressEventHandler (general); // C#1报错,而C#2不报错。

C#1要求两个委托的类型签名必须匹配。

 

 

 本文多数实例均引自《C# in Depth Second Edition》

 

 

 

 

 

 


<script type="text/javascript"><!--google_ad_client = "ca-pub-1944176156128447";/* cnblogs 首页横幅 */google_ad_slot = "5419468456";google_ad_width = 728;google_ad_height = 90;//--></script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
原创粉丝点击