接口上的 C# 泛型隐式转换失败 [英] C# generic implicit cast on Interface failed

查看:36
本文介绍了接口上的 C# 泛型隐式转换失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么下面的不能编译?当 T 是一个接口时,接口有什么特别之处导致编译器认为它不能从 Container 转换为 T?我不认为这是一个协变问题,因为我并没有沮丧,但也许确实如此.这很像 为什么 C# 编译器不调用隐式转换运算符? 但我觉得不太一样.

Why will the below not compile? What's special about the interface that causes the compiler to think it can't cast from Container<T> to T, when T is an interface? I don't think its a covariant issue, as I'm not downcasting, but perhaps it is. This is quite like Why C# compiler doesn't call implicit cast operator? but I don't think it's quite the same.

Product pIn =null;
Product pOut;
Container<Product> pContainer;

List<Product> pListIn = null;
List<Product> pListOut;
Container<List<Product>> pListContainer;

IList<Product> pIListIn = null;
IList<Product> pIListOut;
Container<IList<Product>> pIListContainer;

pContainer = pIn;
pOut = pContainer; // all good

pListContainer = pListIn; 
pListOut = pListContainer; // all good too

pIListContainer = pIListIn; // fails , cant do implicit cast for some reason
pIListOut = pIListContainer; // and here too

<小时>

class Container<T>
{
 private T value;

 private Container(T item) { value = item; }

 public static implicit operator Container<T>(T item)
 {
  return new Container<T>(item);
 }

 public static implicit operator T(Container<T> container)
 {
  return container.value;
 }
}

<小时>

Cannot implicitly convert type 'Container<IList<Product>>' to 'IList<Product>'. An explicit conversion exists (are you missing a cast?)
Cannot implicitly convert type 'IList<Product>' to 'Container<IList<Product>>'. An explicit conversion exists (are you missing a cast?)

推荐答案

界面上根本不允许用户定义的转换.这可能是模棱两可的,因为您尝试从中转换的类型可以实现接口本身——此时转换意味着什么?像普通转换一样的引用转换,还是调用用户定义的转换?

User defined conversions aren't allowed on interfaces at all. It would potentially be ambiguous, because the type you're trying to convert from could implement the interface itself - at which point what would the cast mean? A reference conversion like a normal cast, or an invocation of the user-defined conversion?

来自 C# 4 规范的第 10.3.3 节:

From section 10.3.3 of the C# 4 spec:

对于给定的源类型 S 和目标类型 T,如果 S 或 T 是可空类型,则让 S0 和 T0 指代它们的底层类型,否则 S0 和 T0 分别等于 S 和 T.仅当满足以下所有条件时,才允许类或结构声明从源类型 S 到目标类型 T 的转换:

For a given source type S and target type T, if S or T are nullable types, let S0 and T0 refer to their underlying types, otherwise S0 and T0 are equal to S and T respectively. A class or struct is permitted to declare a conversion from a source type S to a target type T only if all of the following are true:

  • S0 和 T0 是不同的类型.
  • S0 或 T0 是发生运算符声明的类或结构类型.
  • S0 和 T0 都不是接口类型.
  • 排除用户定义的转换,不存在从 S 到 T 或从 T 到 S 的转换.

然后:

但是,可以在泛型类型上声明运算符,对于特定的类型参数,可以将已经存在的转换指定为预定义的转换
...
在两种类型之间存在预定义转换的情况下,这些类型之间的任何用户定义转换都将被忽略.具体:

However, it is possible to declare operators on generic types that, for particular type arguments, specify conversions that already exist as pre-defined conversions
...
In cases where a pre-defined conversion exists between two types, any user-defined conversions between those types are ignored. Specifically:

  • 如果存在从类型 S 到类型 T 的预定义隐式转换(第 6.1 节),则所有用户定义的从 S 到 T 的转换(隐式或显式)都将被忽略.
  • 如果存在从类型 S 到类型 T 的预定义显式转换(第 6.2 节),则忽略任何用户定义的从 S 到 T 的显式转换.此外:
    • 如果 T 是接口类型,则用户定义的从 S 到 T 的隐式转换将被忽略.
    • 否则,仍会考虑用户定义的从 S 到 T 的隐式转换.

    注意这里的第一个嵌套项目符号.

    Note the first nested bullet here.

    (我可以彻底推荐顺便了解一下规范.它可以在 各种版本和格式,但硬拷贝注释版也是团队和其他人的小金矿.我应该在这里承认一定的偏见,因为我是注释者之一 - 但是忽略我的东西,所有其他注释都非常值得阅读!)

    (I can thoroughly recommend getting hold of the spec by the way. It's available online in various versions and formats, but the hardcopy annotated edition is also a goldmine of little nuggets from the team and others. I should confess a certain bias here, as I'm one of the annotators - but ignoring my stuff, all the other annotations are well worth reading!)

    这篇关于接口上的 C# 泛型隐式转换失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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