设计类型
事件
基础概念
-
设计要公开事件的类型
-
第一步: 定义类型来容纳所有需要发送给时间通知接收者的附加信息
// 按实际需求定义类型 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); };
-
-
编译器如何实现事件
- TODO:待分析IL和底层实现代码
-
显示实现事件
/// <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()); } }
泛型
基础概念
- 开放类型和封闭类型
- 具有泛型类型参数的类型称为开放类型,CLR禁止构造开放类型的任何实例
- 为所有类型参数都传递了实际的数据类型,类型就成为封闭类型。
- 代码爆炸
逆变和协变
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.
- 泛型类型参数
- 不变量(invariant):意味着泛型类型参数不能更改。
- 逆变量(contravariant):意味着泛型类型参数可以从一个类更改为他的某个派生类。
- 协变量(covariant):意味着泛型类型参数可以从一个类更改为她的某个基类。
- 简而言之,协变性(covariance)指定返回的类型的兼容性,逆变(contravariance)指定参数的兼容性。
案例
-
方法逆变和协变
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; }
-
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); } }
-
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; }
-
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; } }
约束
- 主要约束
- 可以是代表非密封类的一个引用类型。
- 一个制定的类型实参要么是与约束类型相同的类型,或者约束类型派生的类型。
- 两个特殊的主要约束:class和struct。
- 次要约束
- 可以指定零个或者多个次要约束,次要约束代表接口类型。
- 构造器约束
- new ()
- 主要约束
参考资料
接口
基础概念
- EIMI(显示接口方法实现)
- 用显示接口方法实现类增强编译时类型安全性
/// <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);
}
}
-
显示接口方法实现的弊端
class D1 : IComparable { Int32 IComparable.CompareTo(object obj) { return 0; } } class D2 : D1, IComparable { public Int32 CompareTo(Object o) { // base.CompareTo(o); // 无法读取显示声明的接口 // 改进办法,可以在父类增加虚方法,子类覆写 return 0; } }
设计:基类还是接口
- IS-A对比CAN-DO关系,如果派生类和及类型建立不起IS-A关系,不用基类而用接口。
- 易用性
- 一致性实现
- 版本控制
- 设计建议:
- 建议,定义接口和一个实现它的部分(abstract)或者全部方法(virtual)的基类,提供最大的灵活性。
接口的作用
- 后续补上,或者后续实际应用场景中说明。
网友评论