設(shè)計(jì)類(lèi)型
事件
基礎(chǔ)概念
-
設(shè)計(jì)要公開(kāi)事件的類(lèi)型
-
第一步: 定義類(lèi)型來(lái)容納所有需要發(fā)送給時(shí)間通知接收者的附加信息
// 按實(shí)際需求定義類(lèi)型 internal class XxEventArgs : EventArgs{ public object Yy{get;set;} } -
第二步:定義事件成員
public event EventHandler<T> xxEventHandler; -
第三步:定義負(fù)責(zé)引發(fā)事件的方法來(lái)通知事件的登記對(duì)象
// 支持線(xiàn)程安全 EventHandler<T> temp = Volatile.Read(ref xxEventHandler); if(temp != null){ temp(this,xx); } -
第四步:定義方法將輸入轉(zhuǎn)化為期望的事件
this.eventHandler += (o, e) => { Console.WriteLine("Hehhahah:"+e.HelloWorld); };
-
-
編譯器如何實(shí)現(xiàn)事件
- TODO:待分析IL和底層實(shí)現(xiàn)代碼
-
顯示實(shí)現(xiàn)事件
/// <summary> /// 顯示實(shí)現(xiàn)事件,優(yōu)化 /// </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 { // 私有字典維護(hù)EventKey -> 到Delegate的映射 private readonly ConcurrentDictionary<EventKey, Delegate> _events = new ConcurrentDictionary<EventKey, Delegate>(); public void Add(EventKey eventKey,Delegate handler) { // TODO 理解使用線(xiàn)性安全的字段是否還需要加同步操作 // 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()); } }
泛型
基礎(chǔ)概念
- 開(kāi)放類(lèi)型和封閉類(lèi)型
- 具有泛型類(lèi)型參數(shù)的類(lèi)型稱(chēng)為開(kāi)放類(lèi)型,CLR禁止構(gòu)造開(kāi)放類(lèi)型的任何實(shí)例
- 為所有類(lèi)型參數(shù)都傳遞了實(shí)際的數(shù)據(jù)類(lèi)型,類(lèi)型就成為封閉類(lèi)型。
- 代碼爆炸
逆變和協(xié)變
? In C#, covariance and contravariance enable implicit reference conversion(隱式引用轉(zhuǎn)換 ) for array types, delegate types, and generic type arguments. Covariance preserves assignment compatibility and contravariance reverses it.
- 泛型類(lèi)型參數(shù)
- 不變量(invariant):意味著泛型類(lèi)型參數(shù)不能更改。
- 逆變量(contravariant):意味著泛型類(lèi)型參數(shù)可以從一個(gè)類(lèi)更改為他的某個(gè)派生類(lèi)。
- 協(xié)變量(covariant):意味著泛型類(lèi)型參數(shù)可以從一個(gè)類(lèi)更改為她的某個(gè)基類(lèi)。
- 簡(jiǎn)而言之,協(xié)變性(covariance)指定返回的類(lèi)型的兼容性,逆變(contravariance)指定參數(shù)的兼容性。
案例
-
方法逆變和協(xié)變
static object GetObject() { return null; } static void SetObject(object obj) { } static string GetString() { return ""; } static void SetString(string str) { } static void Test() { // 協(xié)變 // 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; } }約束
- 主要約束
- 可以是代表非密封類(lèi)的一個(gè)引用類(lèi)型。
- 一個(gè)制定的類(lèi)型實(shí)參要么是與約束類(lèi)型相同的類(lèi)型,或者約束類(lèi)型派生的類(lèi)型。
- 兩個(gè)特殊的主要約束:class和struct。
- 次要約束
- 可以指定零個(gè)或者多個(gè)次要約束,次要約束代表接口類(lèi)型。
- 構(gòu)造器約束
- new ()
- 主要約束
參考資料
接口
基礎(chǔ)概念
- EIMI(顯示接口方法實(shí)現(xiàn))
- 用顯示接口方法實(shí)現(xiàn)類(lèi)增強(qiáng)編譯時(shí)類(lèi)型安全性
/// <summary>
/// 用顯示接口方法增強(qiáng)編譯時(shí)類(lèi)型安全性
/// </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);
}
}
-
顯示接口方法實(shí)現(xiàn)的弊端
class D1 : IComparable { Int32 IComparable.CompareTo(object obj) { return 0; } } class D2 : D1, IComparable { public Int32 CompareTo(Object o) { // base.CompareTo(o); // 無(wú)法讀取顯示聲明的接口 // 改進(jìn)辦法,可以在父類(lèi)增加虛方法,子類(lèi)覆寫(xiě) return 0; } }
設(shè)計(jì):基類(lèi)還是接口
- IS-A對(duì)比CAN-DO關(guān)系,如果派生類(lèi)和及類(lèi)型建立不起IS-A關(guān)系,不用基類(lèi)而用接口。
- 易用性
- 一致性實(shí)現(xiàn)
- 版本控制
- 設(shè)計(jì)建議:
- 建議,定義接口和一個(gè)實(shí)現(xiàn)它的部分(abstract)或者全部方法(virtual)的基類(lèi),提供最大的靈活性。
接口的作用
- 后續(xù)補(bǔ)上,或者后續(xù)實(shí)際應(yīng)用場(chǎng)景中說(shuō)明。