C# 为什么要将角色转换为“IEnumerable<;T>;`允许,但必须是“列表”<;T>;`用一般方法
我很确定我没有找到明显的答案,但为什么:C# 为什么要将角色转换为“IEnumerable<;T>;`允许,但必须是“列表”<;T>;`用一般方法,c#,generics,types,casting,C#,Generics,Types,Casting,我很确定我没有找到明显的答案,但为什么: public static void Foo(IEnumerable<string> strings) { } public static void Bar<T>(IEnumerable<T> ts) { Foo((IEnumerable<string>)ts); } publicstaticvoidfoo(IEnumerable字符串){} 公共静态空白栏(IEnumerable ts) {
public static void Foo(IEnumerable<string> strings) { }
public static void Bar<T>(IEnumerable<T> ts)
{
Foo((IEnumerable<string>)ts);
}
publicstaticvoidfoo(IEnumerable字符串){}
公共静态空白栏(IEnumerable ts)
{
Foo((IEnumerable)ts);
}
是允许的,而这:
public static void Foo(List<string> strings) { }
public static void Bar<T>(List<T> ts)
{
Foo((List<string>)ts);
}
publicstaticvoidfoo(列表字符串){}
公共静态空栏(列表ts)
{
Foo((列表)ts);
}
CS0030无法将类型“System.Collections.Generic”转换为类型“System.Collections.Generic”。?两者都有可能在运行时失败,也都有可能在运行时成功。什么样的语言规则支配着这一点?我认为这是以下问题的一个边缘案例:
我同意,在这种情况下,它看起来很奇怪,因为它不可能从扩展字符串的内容中进行转换(字符串类是密封的),但我猜规则是不能将
List
强制转换为List
,因为在t是扩展类SomethingElse或实现接口SomethingElse的类的情况下,可能会调用该方法
e、 g:
public static void Foo(List<string> strings) { }
public static void Bar<T>(List<T> ts)
{
Foo((List<MyInterface>)ts);
}
public static void OtherMethod1()
{
Bar<MyClass>(new List<MyClass>)
}
public static void OtherMethod2()
{
Bar<MyInterface>(new List<MyInterface>)
}
public classs MyClass : MyInterface
{
}
publicstaticvoidfoo(列表字符串){}
公共静态空栏(列表ts)
{
Foo((列表)ts);
}
公共静态void OtherMethod1()
{
酒吧(新名单)
}
公共静态void OtherMethod2()
{
酒吧(新名单)
}
公共类MyClass:MyInterface
{
}
因此,由于可以编写类似于OtherMethod1的方法,但在运行时失败,因此编译器不允许整个场景。不过,同样,密封类似乎是一种奇怪的边缘情况,如果Microsoft愿意,可能会允许这种情况。我认为这是以下问题的边缘情况示例:
我同意,在这种情况下,它看起来很奇怪,因为它不可能从扩展字符串的内容中进行转换(字符串类是密封的),但我猜规则是不能将
List
强制转换为List
,因为在t是扩展类SomethingElse或实现接口SomethingElse的类的情况下,可能会调用该方法
e、 g:
public static void Foo(List<string> strings) { }
public static void Bar<T>(List<T> ts)
{
Foo((List<MyInterface>)ts);
}
public static void OtherMethod1()
{
Bar<MyClass>(new List<MyClass>)
}
public static void OtherMethod2()
{
Bar<MyInterface>(new List<MyInterface>)
}
public classs MyClass : MyInterface
{
}
publicstaticvoidfoo(列表字符串){}
公共静态空栏(列表ts)
{
Foo((列表)ts);
}
公共静态void OtherMethod1()
{
酒吧(新名单)
}
公共静态void OtherMethod2()
{
酒吧(新名单)
}
公共类MyClass:MyInterface
{
}
因此,由于可以编写类似于OtherMethod1的方法,但在运行时失败,因此编译器不允许整个场景。不过,同样,密封类似乎是一种奇怪的边缘情况,如果Microsoft愿意,它可能被允许使用。这是否回答了您的问题?特别是这样一句话:“它是安全的,因为
IEnumerable
不公开任何接受T的方法。”@BagusTesa特别将T定义为仅适用于IEnumerable的out,它强制您声明IEnumerable不接受TNo类型的任何内容,而且“重复”问题似乎也不接受。我知道什么是通用差异,但允许对任意T
进行从IEnumerable
到IEnumerable
的转换是不安全的IEnumerable
必须是协变和逆变,才能在运行时永不失败。这是否回答了您的问题?特别是这样一句话:“它是安全的,因为IEnumerable
不公开任何接受T的方法。”@BagusTesa特别将T定义为仅适用于IEnumerable的out,它强制您声明IEnumerable不接受TNo类型的任何内容,而且“重复”问题似乎也不接受。我知道什么是通用差异,但允许对任意T
进行从IEnumerable
到IEnumerable
的转换是不安全的IEnumerable
必须是协变和逆变,才能在运行时永不失败。但使用T=object
调用IEnumerable
版本也会在运行时失败,但这是允许的。为什么?强制转换允许在运行时失败。编译器不允许的是可以工作的强制转换,但在尝试调用强制转换类型上的有效方法时失败。在IEnumerable上,如果您从T转换到对象,并且转换成功,则没有任何方法会中断。这是一份清单。请参阅链接的示例/duplicate。但是使用T=object
调用IEnumerable
版本也会在运行时失败,但这是允许的。为什么?强制转换允许在运行时失败。编译器不允许的是可以工作的强制转换,但在尝试调用强制转换类型上的有效方法时失败。在IEnumerable上,如果您从T转换到对象,并且转换成功,则没有任何方法会中断。这是一份清单。请参阅链接的示例/副本。