C# 从1.0 到现在的4.0,在每一个新的版本中都增加了一些激动人心的特性。 2.0 增加了对泛型的支持,3.0 增加了对LINQ的支持,而在4.0 中则最大的更新则就是对动态语言等特性的支持!
动态类型绑定
动态类型绑定就是指将解析类型和成员的过程由编译时延迟到运行时。C#是一种强数据类型的语言,因此要求在编译时就决定了数据的类型。即使是用关键字Var 的隐士类型声明,在编译时也会变成确切的数据类型。而动态绑定则允许在编译时可以不知道数据的确切类型,等在运行时才决定数据的确切类型。
例如:
public class DyTypeObject :DynamicObject
{
public override bool TryInvokrmember( InvokeMemberBinder binder,Object[] args,out object result)
{
Console.WriteLine(binder.Name +"方法正在调用");
result = null;
return true;
}
}
class Program
{
static void Main(String [] args)
{
dynamic obj = new DyTypeObject();
obj.Working();
obj.WorkingOthers();
Console.Writeline();
}
}
从上面可以看到,working() 和WorkingOthers() 方法并没有定义,但运行时能够成功调用。
泛型类型的协变和逆变
什么是协变和逆变呢?这编程语言中,协变是指能够使用与原始指定的派生类型相比派生程度更大的类型,也就是可以使用原始指定类型的子类型。逆变则是指能够使用比原始指定类型派生程度更小的类型,也就是说能够使用原始指定类型的父类型。泛型类型的协变与逆变是在4.0才增加的。但是以前C#就支持了委托类型的参数的协变与逆变。
下面我来看一个关于委托类型参数协变的一个例子
public class Animals
{
public string Loacation{ get; set; }
}
public class Dogs :Animals
{
public string Cry{ get; set; }
}
class program
{
public delegate Animals HandlerMethod();
public static Animals FirstHandler()
{
Console.WriteLine("返回Animals类型的委托");
return null;
}
public static Dogs SecondHandler()
{
Console.WriteLine(" 放回Dogs 类型的委托");
return null;
}
static void Main ( string[] args )
{
HandlerMethod handler1 = FirstHandler; // 标准委托
HandlerMethod handler2 = SecondHandler; // 协变委托
}
}
在上面的代码中,首先定义了Animals 和 Dogs 类, 然后定义了一个返回类型为Animals 的委托 HandlerMethod. 在Main函数里分别给这个委托赋值一个返回Animals 和Dogs 类型的方法。因此可以看出,由于委托的协变性使得本来返回类型为Animals 的委托可以接受一个返回类型为Dogs 的方法。
在.Net 4.0 中通过引入in/out 参数来实现泛型的协变与逆变。比如定义一个泛型接口或者委托,就可以使用out 关键字,将泛型参数声明为协变的。协变类型必须满足的条件是: 协变仅用作接口方法的返回类型,而不用作方法的参数类型。可以使用in 关键字,将泛型接口参数声明为逆变的,逆变只能作用于泛型接口方法的参数类型,而不能作用泛型接口方法的返回类型。
泛型的协变
Interfance ITest<out T>
{
T X { get ;} //返回类型为T的属性
T M(); //返回类型为T的方法
}
class TestClass<T> :ITest<T>
Where T : Base、new () // 约束T要派生自Base ,具有构造函数
{
Public T X { get; set; }
public T M()
{
return new T ();
}
}
class Base {}
class Derived : Base {}
class Program
{
static void Main (string[] args)
{
ITest<Derived> dervied = new TestClass<Derived>{ X = new Devied()};
ITest<Base> base = dervied; // 泛型的协变
Base x = base.X
Base m = base.M();
}
}
与协变相反,逆变是将基类型转换为派生类型,泛型的逆变有以下两条规则:
● 泛型参数受In 关键字的约束,只能用于属性设置或委托(方法)参数。
●隐式转换目标的泛型参数类型必须是当前类型的继承类。
接口的逆变
interface ITest< in T>
{
T X
{
get; // 获取属性不允许逆变
set; // 设置属性允许逆变
}
T M ( T o); // 只允许方法参数逆变,方法参数不能逆变
}