美文网首页
设计类型(三)

设计类型(三)

作者: 沈_ac89 | 来源:发表于2019-03-08 00:28 被阅读0次

    设计类型

    事件

    基础概念

    1. 设计要公开事件的类型

      • 第一步: 定义类型来容纳所有需要发送给时间通知接收者的附加信息

        // 按实际需求定义类型
        internal class XxEventArgs : EventArgs{
            public object Yy{get;set;}
        }
        
      • 第二步:定义事件成员

        public event EventHandler<T> xxEventHandler;
        
      • 第三步:定义负责引发事件的方法来通知事件的登记对象

        // 支持线程安全
        EventHandler<T> temp = Volatile.Read(ref xxEventHandler);
        if(temp != null){
            temp(this,xx);
        }
        
      • 第四步:定义方法将输入转化为期望的事件

        this.eventHandler += (o, e) => {
           Console.WriteLine("Hehhahah:"+e.HelloWorld);
        };
        
    1. 编译器如何实现事件

      • TODO:待分析IL和底层实现代码
    2. 显示实现事件

          /// <summary>
          ///  显示实现事件,优化
          /// </summary>
          public  class B
          {
              private readonly EventSet _eventSet = new EventSet();
      
              protected EventSet EventSet { get { return _eventSet; } }
      
              protected static readonly EventKey _fooEventKey = new EventKey();
      
              public event EventHandler<XxEventArgs> Foo {
                  add { _eventSet.Add(_fooEventKey, value);
                  }
                  remove { _eventSet.Remove(_fooEventKey, value); }
              }
      
              protected virtual void OnFoo(XxEventArgs e)
              {
                  _eventSet.Raise(_fooEventKey, this, e);
              }
      
              public void SimulateFoo()
              {
                  OnFoo(new XxEventArgs { });
              }
          }
      
          public class XxEventArgs : EventArgs {
              public override string ToString()
              {
                  return "Hello,World";
              }
          }
      
          public sealed class EventKey { }
      
          public sealed class EventSet
          {
              // 私有字典维护EventKey -> 到Delegate的映射
              private readonly ConcurrentDictionary<EventKey, Delegate> _events = new ConcurrentDictionary<EventKey, Delegate>();
      
              public void Add(EventKey eventKey,Delegate handler)
              {
                  // TODO 理解使用线性安全的字段是否还需要加同步操作
                  // Monitor.Enter(_events);
                  Delegate d;
                  _events.TryGetValue(eventKey, out d);
                  _events[eventKey] = Delegate.Combine(d, handler);
                  // Monitor.Exit(_events);
              }
      
              public void Remove(EventKey eventKey,Delegate handler)
              {
                  // Monitor.Enter(_events);
                  Delegate d;
                  if(_events.TryGetValue(eventKey,out d))
                  {
                      d = Delegate.Remove(d, handler);
                      if (d != null)
                      {
                          _events[eventKey] = d;
                      }
                      else
                      {
                          _events.TryRemove(eventKey,out d);
                      }
                  }
                  // Monitor.Exit(_events);
              }
      
              public  void Raise(EventKey eventKey,Object sender,EventArgs e)
              {
                  Delegate d;
                  // Monitor.Enter(_events);
                  _events.TryGetValue(eventKey, out d);
                  //  Monitor.Exit(_events);
                  if (d != null)
                  {
                      d.DynamicInvoke(new object[] { sender,e});
                  }
              }
          }
      
          public sealed class BDemo
          {
              public void Run()
              {
                  B b = new B();
                  b.Foo += B_Foo;
                  b.SimulateFoo();
              }
      
              private void B_Foo(object sender, XxEventArgs e)
              {
                  Console.WriteLine(e.ToString());
              }
          }
      

    泛型

    基础概念

    1. 开放类型和封闭类型
      • 具有泛型类型参数的类型称为开放类型,CLR禁止构造开放类型的任何实例
      • 为所有类型参数都传递了实际的数据类型,类型就成为封闭类型。
    2. 代码爆炸

    逆变和协变

    ​ In C#, covariance and contravariance enable implicit reference conversion(隐式引用转换 ) for array types, delegate types, and generic type arguments. Covariance preserves assignment compatibility and contravariance reverses it.

    1. 泛型类型参数
      • 不变量(invariant):意味着泛型类型参数不能更改。
      • 逆变量(contravariant):意味着泛型类型参数可以从一个类更改为他的某个派生类。
      • 协变量(covariant):意味着泛型类型参数可以从一个类更改为她的某个基类。
    2. 简而言之,协变性(covariance)指定返回的类型的兼容性,逆变(contravariance)指定参数的兼容性。

    案例

    1. 方法逆变和协变

      static object GetObject() { return null; }  
      static void SetObject(object obj) { }  
        
      static string GetString() { return ""; }  
      static void SetString(string str) { }  
        
      static void Test()  
      {  
          // 协变
          // Covariance. A delegate specifies a return type as object,  
          // but you can assign a method that returns a string.  
          Func<object> del = GetString;  
        
          // 逆变
          // Contravariance. A delegate specifies a parameter type as string,  
          // but you can assign a method that takes an object.  
          Action<string> del2 = SetObject;  
      }  
      
    2. Using Variance in Interfaces for Generic Collections (C#)

      // Simple hierarchy of classes.  
      public class Person  
      {  
          public string FirstName { get; set; }  
          public string LastName { get; set; }  
      }  
        
      public class Employee : Person { }  
        
      class Program  
      {  
          // The method has a parameter of the IEnumerable<Person> type.  
          public static void PrintFullName(IEnumerable<Person> persons)  
          {  
              foreach (Person person in persons)  
              {  
                  Console.WriteLine("Name: {0} {1}",  
                  person.FirstName, person.LastName);  
              }  
          }  
        
          public static void Test()  
          {  
              IEnumerable<Employee> employees = new List<Employee>();  
        
              // You can pass IEnumerable<Employee>,   
              // although the method expects IEnumerable<Person>.  
        
              PrintFullName(employees);  
        
          }  
      }
      
    3. Convariance In Delegate

      // Event handler that accepts a parameter of the EventArgs type.  
      private void MultiHandler(object sender, System.EventArgs e)  
      {  
          label1.Text = System.DateTime.Now.ToString();  
      }  
        
      public Form1()  
      {  
          InitializeComponent();  
        
          // You can use a method that has an EventArgs parameter,  
          // although the event expects the KeyEventArgs parameter.  
          this.button1.KeyDown += this.MultiHandler;  
        
          // You can use the same method   
          // for an event that expects the MouseEventArgs parameter.  
          this.button1.MouseClick += this.MultiHandler;  
        
      }
      
    4. Covariance In Delegate

      class Mammals {}  
      class Dogs : Mammals {}  
        
      class Program  
      {  
          // Define the delegate.  
          public delegate Mammals HandlerMethod();  
        
          public static Mammals MammalsHandler()  
          {  
              return null;  
          }  
        
          public static Dogs DogsHandler()  
          {  
              return null;  
          }  
        
          static void Test()  
          {  
              HandlerMethod handlerMammals = MammalsHandler;  
        
              // Covariance enables this assignment.  
              HandlerMethod handlerDogs = DogsHandler;  
          }  
      }
      

      约束

      1. 主要约束
        • 可以是代表非密封类的一个引用类型。
        • 一个制定的类型实参要么是与约束类型相同的类型,或者约束类型派生的类型。
        • 两个特殊的主要约束:class和struct。
      2. 次要约束
        • 可以指定零个或者多个次要约束,次要约束代表接口类型。
      3. 构造器约束
        • new ()

    参考资料

    1. wikipedia's Covariance and contravariance (computer science)
    2. 大牛Eric Lippert
    3. 微软MSDN文档-逆变和协变

    接口

    基础概念

    1. EIMI(显示接口方法实现)
    2. 用显示接口方法实现类增强编译时类型安全性
        /// <summary>
        /// 用显示接口方法增强编译时类型安全性
        /// </summary>
        struct D : IComparable
        {
            private Int32 _x;
    
            public D(Int32 x)
            {
                this._x = x;
            }
    
            public int CompareTo(D o)
            {
                return o._x - this._x;
            }
    
            Int32 IComparable.CompareTo(object obj)
            {
                return CompareTo((D)obj);
            }
        }
    
    1. 显示接口方法实现的弊端

          class D1 : IComparable
          {
              Int32 IComparable.CompareTo(object obj)
              {
                  return 0;
              }
          }
      
          class D2 : D1, IComparable
          {
              public Int32 CompareTo(Object o) {
                  // base.CompareTo(o); // 无法读取显示声明的接口
                  // 改进办法,可以在父类增加虚方法,子类覆写
                  return 0;
              }
          }
      

    设计:基类还是接口

    1. IS-A对比CAN-DO关系,如果派生类和及类型建立不起IS-A关系,不用基类而用接口。
    2. 易用性
    3. 一致性实现
    4. 版本控制
    5. 设计建议:
      • 建议,定义接口和一个实现它的部分(abstract)或者全部方法(virtual)的基类,提供最大的灵活性。

    接口的作用

    • 后续补上,或者后续实际应用场景中说明。

    相关文章

      网友评论

          本文标题:设计类型(三)

          本文链接:https://www.haomeiwen.com/subject/aekfpqtx.html