委托
委托
委托:委托是一種安全地封裝方法的引用類型,他是面向對象的、類型安全的和保險的,它可以代理一個或是多個方法,或是代碼塊執行,由于是引用類型,它保存的不是實際值,而是保存對存儲在托管堆中的對象的引用,即對函數的引用。
構造委托對象的方法:
命名方法:使用命名方法構造的委托可以封裝靜態方法或實例方法(當然定義定義委托的時候不能用static修飾,靜態方法不能調用實例化方法),命名方法代理的是方法。
public delegate void SampleDelegate(string message);
public static void SampleDelegateMethod(string message)
{
Console.WriteLine("SampleDelegateMethod:" + message);
}
SampleDelegate d1 =new SampleDelegate(SampleDelegateMethod);
//可以簡寫成
SampleDelegate d1 = SampleDelegateMethod;
d1("chentaihan");
匿名方法:匿名方法代理的是一段代碼塊,使用匿名方法,則不必創建單獨的方法,因此減少了實例化委托所需的編碼系統開銷。
SampleDelegate d2 = delegate(string message)
{
Console.WriteLine(message);
};
d2("chentaihan");
委托中的協變與逆變
協變實例如下
public class Animal
{
public Animal(string name)
{
this.Name = name;
}
protected string Name;
public virtual void ShowName()
{
Console.WriteLine("Animal:" + Name);
}
};
public class Cat : Animal
{
public Cat(string name) : base(name) { }
public override void ShowName()
{
Console.WriteLine("Cat:" + Name);
}
}
public delegate Animal DelegateAnimalXB(string name);
public class DelegateXB
{
public static Animal CreateAnimal(string name)
{
return new Animal(name);
}
public static Cat CreateCat(string name)
{
return new Cat(name);
}
public static void Test()
{
DelegateAnimalXB d1 = CreateAnimal;
d1("Animal").ShowName();//Animal:Animal
DelegateAnimalXB d2 = CreateCat;
d2("Cat").ShowName();//Cat:Cat
}
}
委托協變講的是定義委托是返回類型的多態,我覺得重點根本不在委托,這其實還是一個類型轉換的問題,定義委托時返回類型未Animal,你返回他的之類Cat,沒有問題啊,編譯器幫你隱式類型轉換啊,就這樣。
委托逆變實例如下:
public class MyEventArgs : EventArgs
{
public MyEventArgs(){}
}
public class DelegateNB
{
public delegate void Handler(EventArgs e);
public event Handler eventHandler;
public void Test(EventArgs e)
{
eventHandler(e);
}
}
static void Main(string[] args)
{
DelegateNB nb = new DelegateNB();
nb.eventHandler += new DelegateNB.Handler(Test);
nb.Test(new MyEventArgs());
Console.Read();
}
public static void Test(EventArgs e)
{
Console.WriteLine(e.ToString());
}
}
委托的逆變看上去實現了參數的多態,定義委托的時候,參數為EventArgs,而傳進去的卻是一個MyEventArgs,但是定義其他類型的參數,使用多態的方式傳參卻編譯通過不了,只能是EventArgs及其之類,為什么是這樣呢,俺也不知道,只知道事件代理的時候,定義委托的時候參數絕對是(object sender,EventArgs e),微軟只用定義這一個事件,他就能委托很多類型的事件,如mouseup,mousedown,keyup等一堆類似的事件,正 因為定義委托的時候參數類型未EventArgs,所以你在寫事件方法的時候參數為EventArgs或是相關的事件類(肯定也是EventArgs的之類)都是可以的。如文本框的KeyDown事件參數為KeyEventArgs,你用EventArgs是沒有問題的,因為委托定義的時候參數就是EventArgs嗎,當然用EventArgs沒有會失去KeyEventArgs自帶的屬性和方法,反過來說如果我們不需要這些特有的屬性和方法,用EventArgs會更好,殺雞焉用宰牛刀。
泛型委托
泛型委托就會泛型跟委托的結合,根本不是什么新東西,只要你會泛型,會用委托,你就知道怎么使用泛型委托。泛型委托其實就是編譯器動態的幫你定義一組委托,在你要用得時候才定義,不用就不定義,而且每種類型的委托只定義一次。泛型說白了就是編譯器幫你寫代碼,當然使用他的確是減少了類型轉換。
簡單實例如下:
public class DelegateGeneric
{
public delegate void Del<T>(T item);
public static void f1(double i)
{
Console.WriteLine(i);
}
public static void Test()
{
Del<double> d1 = f1;
d1(1);//代理方法f1(double i),輸出:1
}
}
委托不能重載,即委托名稱相同,參數類型,個數不同。構造委托的時候,根本不管參數,當然也就不知道你要構造的是哪個委托。
委托不支持多態,正因為重載的存在導致委托不能支持多態。
public class A { }
public class B : A { }
public class DelegateDT
{
public delegate void DelegateFun(A a);
public static void DelegateA(A a)
{
Console.WriteLine("DelegateA");
}
public static void DelegateA(B a)
{
Console.WriteLine("DelegateB");
}
public static void Test()
{
DelegateFun d1 = DelegateA;
d1(new B());
}
}
這里其實調用的是方法DelegateA(A a),并不是DelegateA(B a),要是支持多態的話,他根本就不知道調用哪個方法,還是因為多態,你傳進來一個對象B,正好有一個方法所需的參數是B的父類A,所以編譯器自動將B隱式轉換成A,然后調用方法DelegateA(A a),如果沒有這個方法,編譯是通不過的。多態不就是編譯器幫我們尋找最合適的方法嗎,如果沒找到,就隱式轉換,看有沒有合適的方法,如果沒有,編譯出錯。
作者:陳太漢
浙公網安備 33010602011771號