前言:C#1中就已经有了委托的观点,但是其繁杂的用法并没有引起开发者太多的存眷,在C#2中,进行了一些编译器上的优化,可以用匿名要领来创建一个委托。同时,还撑持的要领组和委托的转换。趁便的,C#2中增加了委托的协变和逆变。
要领组转换要领组这个词的含义来自于要领的重载:我们可以界说一堆要领,这堆要领的名称都一样,但是接受的参数差别或者返回类型差别(总之就是签名差别----除了名字),这就是要领的重载。
public static void SomeMethod(object helloworld)
{
Console.WriteLine(helloworld);
}
public static void SomeMethod()
{
Console.WriteLine("hello world");
}
ThreadStart ts = SomeMethod;
ParameterizedThreadStart ps = SomeMethod;
上面显示的两个挪用没有问题,编译器能够找到与之匹配的相应要领去实例化相应的委托,但是,问题在于,对付自己已经重载成使用ThreadStart和ParameterizedThreadStart的Thread类来说(这里是举例,固然适用于所有这样的情况),传入要领组会导致编译器报错:
Thread t=new Thread(SomeMethod); //编译器报错:要领挪用具有二义性
同样的情况不能用于将一个要领组直接转换成Delegate,需要显式的去转换:
Delegate parameterizedThreadStart = (ParameterizedThreadStart) SomeMethod; Delegate threadStart = (ThreadStart) SomeMethod;
协变性和逆变性C#1并不撑持委托上面的协变性和逆变性,这意味着要为每个委托界说一个要领去匹配。C#2撑持了委托的协变和逆变,这意味着我们可以写下如下的代码:
假定两个类,此中一个担任另一个:
public class BaseClass { } public class DerivedClass : BaseClass { }
C#2撑持如下写法:
class Program { delegate BaseClass FirstMethod(DerivedClass derivedClass); static void Main(string[] args) { FirstMethod firstMethod = SomeMethod; Console.ReadKey(); } static DerivedClass SomeMethod(BaseClass derivedClass) { return new DerivedClass(); } }
而在C#4中,撑持了泛型类型和泛型委托的协变和逆变:
public class BaseClass{}
public class DerivedClass : BaseClass{}
Func<BaseClass, DerivedClass> firstFunc = delegate(BaseClass baseClass)
{ return new DerivedClass(); };Func<DerivedClass, BaseClass> secondFunc = firstFunc;
素质上C#4泛型上的协变和逆变只是引用之间的转换,并没有在后面创建一个新的东西。
不兼容的危害C#2撑持了委托协变和逆变后会呈现下面的问题:
假设此刻BaseClass和DerivedClass改为下面这样的:
public class BaseClass { public void CandidateAction(string x) { Console.WriteLine("Baseclass.CandidateAction"); } } public class DerivedClass : BaseClass { public void CandidateAction(object x) { Console.WriteLine("Derived.CandidateAction"); } }
在DerivedClass中重载了BaseClass中的要领,由于C#2的泛型逆变和协变,写下如下代码:
class Program { delegate void FirstMethod(string x); static void Main(string[] args) { DerivedClass derivedClass=new DerivedClass(); FirstMethod firstMethod = derivedClass.CandidateAction; firstMethod("hello world");//DerivedClass.CandidateAction Console.ReadKey(); } }
输出功效是”DerivedClass.CandidateAction!看到的这个功效必定是在C#2以及以后的功效,如果在C#1中,那么该功效应该是输出“BaseClass.CandidateAction"
匿名要领下面这个进场的匿名要领是我们之后学习linq和lambda等等一系列重要观点的始作俑者。
首先他要解决的问题是C#1中的委托挪用起来太繁琐的问题。在C#1中,要成立一个委托并使用这个委托的话凡是要经历四部,关键是不管你要挪用一个何等简单的委托都要写一个专门被委托挪用的要领放到类里面,如果没有合适的类的话你还要新建一个类。。。