泛型协方差和显式铸造 [英] generics covariance and explicit casting

查看:137
本文介绍了泛型协方差和显式铸造的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我尝试做:

  IDictionary< uint,IEnumerable< string>> dict = new Dictionary< uint,List< string>>(); 

我收到错误消息:


错误CS0266:无法隐式转换类型
'System.Collections.Generic.Dictionary>'

'System.Collections.Generic.IDictionary>'。
存在明确的转换(您是否缺少演员?)

如果我添加演员:

  IDictionary< uint,IEnumerable< string>> dict =(IDictionary< uint,IEnumerable< string>>)new Dictionary< uint,List< string>>(); 

然后编译。



为什么我需要明确的演员?它安全吗?编辑:
C#可以防止无关联的铸造例如
p>

  string s =(string)0L; 




错误CS0030:无法将类型'long'转换为'string'

当您知道对象实际上是一个子类时,它确实允许显式向下转换相关类型:

  Animal animal = new Cat(); 
猫猫=(猫)动物;

我很困惑为什么编译器会提供,并且允许我明确地转换为具有不兼容类型的IDictionary 。

解决方案

这是不安全的。例如,你现在可以编写 dict.Add(5,new string [0]),这会爆炸,因为 string [] 不是列表< string>

编辑以解决您最新的担忧:



不安全的事实是您需要投射的原因。 C#允许从任何引用类型S到任何接口T的任何显式类型转换(提供的S不密封,并且提供的S不实现T.)。此行为在语言规范的第6.2.4节中指定。所以这是合法的:

  var foo =(IList< ICollection< IEnumerable< IntPtr>>>)new Uri(@ http://zombo.com); 

我不能说为什么会出现这种情况,除了C#类型系统是原本甚至比今天更受约束(例如,没有泛型,没有变化),所以我确信有很多情况下能够通过演员阵容绕过它非常方便。

If I try and do:

IDictionary<uint, IEnumerable<string>> dict = new Dictionary<uint, List<string>>();

I get the error:

error CS0266: Cannot implicitly convert type 'System.Collections.Generic.Dictionary>' to 'System.Collections.Generic.IDictionary>'. An explicit conversion exists (are you missing a cast?)

If I add the cast:

IDictionary<uint, IEnumerable<string>> dict = (IDictionary<uint, IEnumerable<string>>)new Dictionary<uint, List<string>>();

Then it compiles.

Why do I need the explicit cast? And is it safe? I thought the whole point on covariance was the ability to implicitly cast safely?

EDIT: C# prevents unrelated casting eg

string s = (string)0L;

error CS0030: Cannot convert type 'long' to 'string'

It does allow explicit downcasting of related types when you know that the object is actually a subclass:

Animal animal = new Cat();
Cat cat = (Cat)animal;

I am confused why the compiler is offering, and allowing me to explicitly cast to an IDictionary with incompatible types.

解决方案

It is not safe. For example, you could now write dict.Add(5, new string[0]), which would blow up, since a string[] is not a List<string>. The fact that it is unsafe is why you need the cast.

Edit to address your updated concern:

C# allows any explicit cast from any reference type S to any interface T ("provided S is not sealed and provided S does not implement T.") This behavior is specified in section 6.2.4 of the language spec. So this is legal:

var foo = (IList<ICollection<IEnumerable<IntPtr>>>)new Uri(@"http://zombo.com");

I can't say why this is the case, other than the fact that the C# type system was originally even more constrained than it is today (e.g. no generics, no variance) so I'm sure that there were a lot of cases in which being able to hack around it with casts was very convenient.

这篇关于泛型协方差和显式铸造的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆