Visual Studio 2010与c#4.0新特性--Variance-变性
Posted 尹成
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Visual Studio 2010与c#4.0新特性--Variance-变性相关的知识,希望对你有一定的参考价值。
Variance变性
泛型的某个方面会让人感到奇怪,比如下面的代码是不合法的——
IList<string> strings = new List<string>();
IList<object> objects = strings;
第二个赋值是不允许的,因为strings和objects的元素类型并不一样。这样做有这充分的原因。如果允许那样写的话,你可能会写——
objects[0] = 5;
string s = strings[0];
这会允许将int插入strings列表中,然后将其作为string取出。这会破坏类型安全。
然而,对于某些接口来说上述情况并不会发生,尤其是不能将对象插入集合时。例如IEnumerable<T>就是这样的接口。如果改为——
IEnumerable<object> objects = strings;
这样就没法通过objects将错误类型的东西插入到strings中了,因为objects没有插入元素的方法。变性(variance)就是用于在这种能保证安全的情况下进行赋值的。结果就是很多之前让我们感到奇怪的情况现在可以工作了。
Covariance
协变性
在.NET 4.0中,IEnumerable<T>接口将会按照下面的方式进行定义——
public interface IEnumerable<out T> : IEnumerable
IEnumerator<T> GetEnumerator();
public interface IEnumerator<out T> : IEnumerator
bool MoveNext();
T Current get;
这些声明中的“out”指出T只能出现在接口的输出位置——如果不是这样的话,编译器会报错。有了这一限制,接口对于T类型就是“协变的”,这意味着如果A可以按引用转换为B,则IEnumerable<A>可以当作IEnumerable<B>使用。
其结果是,任何一个字符串序列也就是一个对象序列了。
这很有用,例如在LINQ方法中。使用上面的定义——
var result = strings.Union(objects);
之前这样做是不允许的,你必须做一些麻烦的包装,使得两个序列具有相同的元素类型。
Contravariance
逆变性
类型参数还可以具有“in”修饰符,限制它们只能出现在输入位置上。例如IComparer<T>——
public interface IComparer<in T>
public int Compare(T left, T right);
其结果有点让人迷惑,就是IComparer<object>可以作为IComparer<string>使用!这样考虑这个结果就会很有意义——如果一个比较器可以比较任意两个object,它当然也可以比较两个string。这种性质被称作“逆变性(contravariance)”。
泛型类型可以同时拥有带有in和out修饰符的类型参数,例如Func<...>委托类型——
public delegate TResult Func<in TArg, out TResult>(TArg arg);
很明显参数永远都是传入的,而结果永远只能是传出的。因此,Func<object, string>可以用作Func<string, object>。
具体时间代码见下面,在VS2010与 windows7的环境调试成功
以上是关于Visual Studio 2010与c#4.0新特性--Variance-变性的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server Compact 4.0 未在 Visual Studio 2010 中显示
我可以在 Windows XP 上使用 Visual Studio 2010 远程调试器从 Visual Studio 2012 调试 .Net 4.0 应用程序吗?
我可以使用 Visual Studio 2010 而不升级到 .NET Framework 4.0 吗?
参考 DLL 未在 Visual Studio 2010 中加载