ITPub博客

首页 > Linux操作系统 > Linux操作系统 > VS2010 C#4.0中的新功能协变性和逆变性

VS2010 C#4.0中的新功能协变性和逆变性

原创 Linux操作系统 作者:wawa2341521 时间:2010-06-28 17:00:10 0 删除 编辑

VS2010的推出会为我们带来新版本的C#。了解C#4.0中的新功能有助于我们利用编码。它还能够帮助我们了解程序中正在出现,而下一代的C#有可能会解决的错误。最终,这样的实践可以帮助我们在现有的知识结构上创建适应C#4.0的业务。

 

  在本文中我们关注的是C# 4.0中的协变性和逆变性。

 

  恒定性,协变性和逆变性

 

  在进一步研究问题之前,我们先解释一下恒定性,协变性,逆变性参数以及返回类型这些概念的意思。大家对这些概念应该是熟悉的,即便那你可能并不能把握这些概念的正式定义。

 

  如果你必须使用完全匹配正式类型的名称,那么返回的值或参数是不变的。如果你能够使用更多的衍生类型作为正式参数类型的代替物,那么参数是可变的。如果你能够将返回的类型分配给拥有较少类型的变量,那么返回的值是逆变的。

 

  在大多数情况下,C#支持协变参数和逆变的返回类型。这一特性也符合其他所有的对象指向型语言。事实上,多态性通常是建立在协变和逆变的概念之上的。直观上,我们发现是可以将衍生的类对象发送给任何期望基类对象的方法。比较,衍生的对象也是基类对象的实例。本能地我们也清楚,我们可以将方法的结果保存在拥有较少衍生对象类型的变量中。例如,你可能会需要对这段代码进行编译:

 

public static void PrintOutput(object thing) 

{

 

if (thing != null)

 

Console.WriteLine(thing);

 

}

 

// elsewhere:

 

PrintOutput(5);

 

PrintOutput("This is a string");

 

 

  这段代码之所以有效是因为参数类型在C#中具有协变性,你可以将任意方法保存在类型对象的变量中,因为C#中返回类型是逆变的:

 

 object value = SomeMethod();

 

  如果在.net推出后,你已经了解C#或VB.NET,那么你应该很熟悉以上的内容。但是规则发生了一些改变。在很多方法中,你直觉上认为有效的其实不然。随着你渐渐深入了解,会发现你曾经认为是漏洞的东西很可能是该语言的说明。现在是时候解释一下为什么集合以不同的方式工作,以及未来将发生些什么变化。

 

  基于对象的集合

 

  .NET 1.x集合(ArrayList,HashTable,Queue等)可以被视为具有协变性。遗憾的是,它们不具有安全的协变性。事实上,它们具有恒定性。不过由于它们向System.Object保存了参考,它们看上去像是具有了协变性和逆变性。举几个例子就可以说明这个问题。

 

你可以认为这些集合是协变的,因为你可以创建一个员工对象的数组列表,然后使用这个列表作为任意方法的参数,这些方法使用的是类型数组列表的对象。通常这种方法很有效。这个方法可能能够与数组列表连用:

 

private void SafeCovariance(ArrayList bunchOfItems) 

{

 

foreach(object o in bunchOfItems)

 

Console.WriteLine(o);

 

// reverse the items:

 

int start = 0;

 

int end = bunchOfItems.Count - 1;

 

while (start < end)

 

{

 

object tmp = bunchOfItems[start];

 

bunchOfItems[start] = bunchOfItems[end];

 

bunchOfItems[end] = tmp;

 

start++;

 

end--;

 

}

 

foreach(object o in bunchOfItems)

 

Console.WriteLine(o);

 

}

 

  这个方法是安全的因为它没有改变集合中任何对象的类型。它列举了集合并将集合中已有的项目移动到了不同索引。不过并未改变任何类型,因此这个方法适用于所有实例。但是数组列表和其他传统的.NET 1.x集合不会被视为安全的协变。看这一方法:

 

private void UnsafeUse(ArrayList stuff) 

{

 

for (int index = 0; index < stuff.Count; index++)

 

stuff[index] = stuff[index].ToString();

 

}

 

这是对保存在集合中的作出的更深一层的假设。当方法存在时候,集合包含了类型字符串的对象。或许这不再是原始集合中的类型。事实上,如果原始集合包含这些字符串,那么方法就不会产生效果。否则,它会将集合转换为不同的类型。下列使用实例显示了在调用方法的时候遇到的各种问题。此处,一列数字被发送到了UnsafeUse,而数字正是在此处被转换成了字符串的数组列表。调用以后,呼叫代码会尝试再一次创建能够导致InvalidCastException的项目。

 

 // usage: 

public void DoTest()

 

{

 

ArrayList collection = new ArrayList()

 

{

 

1,2,3,4,5,6,7, 8, 9, 10,

 

11,12,13,14,15,16,17,18,19,20,

 

21,22,23,24,25,26,27,28,29,30

 

};

 

SafeCovariance(collection);

 

// create the sum:

 

int sum = 0;

 

foreach (int num in collection)

 

sum += num;

 

Console.WriteLine(sum);

 

UnsafeUse(collection);

 

// create the sum:

 

sum = 0;

 

try

 

{

 

foreach (int num in collection)

 

sum += num;

 

Console.WriteLine(sum);

 

}

 

catch (InvalidCastException)

 

{

 

Console.WriteLine(

 

"Not safely covariant");

 

}

 

}

 

 

  这个例子表明虽然典型的集合是不变的,但是你可以视它们为可变或可逆变。不过这些集合并非安全可变。编译器难保不会出现失误。

 

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/9914327/viewspace-666512/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2010-06-19

  • 博文量
    3
  • 访问量
    2915