密封关键字影响编译器对转换的意见 [英] Sealed keyword affects the compiler's opinion on a cast
问题描述
我有一种情况,我想编译器的行为解释。给定一个小代码:
interface IFoo< T>
{
T Get();
}
class FooGetter:IFoo< int>
{
public int Get()
{
return 42;
}
}
以下编译和运行:
static class FooGetterGetter
{
public static IFoo< T> Get< T>()
{
return(IFoo< T>)new FooGetter
}
}
如果我们更改 Foo
类并添加密封
关键字:
sealed class FooGetter:IFoo< int> // etc
然后我在下面一行中遇到编译错误:
return(IFoo< T>)new FooGetter
其中:
无法将类型MyNamespace.FooGetter转换为MyNamespace.IFoo< T>'
关于 sealed
关键字?这是在Visual Studio 2010中的.NET 4项目的C#4.
更新:有趣的是,我偶然发现了这部分行为,我想知道为什么下面的代码修复它 sealed
时应用:
return(IFoo< T>)(IFoo< int>)new FooGetter();
更新:只是为了说明, T
请求与具体类型使用的 T
类型相同。如果类型不同,则转型在运行时会失败,类似于:
无法转换类型为MyNamespace.StringFoo b $ b'MyNamespace.IFoo`1 [System.Int32]'
在上面的示例中, StringFoo :IFoo< string>
,并且调用者要求获得 int
。
FooGetter
是 IFoo< int>
的显式实现而不是实现 IFoo< T>
。由于它是密封的,编译器知道没有办法把它转换为通用的 IFoo
如果 T
是除了 int
之外的任何东西。如果它没有被密封,编译器将允许它在运行时编译并抛出一个异常,如果 T
不是 int
。 如果您尝试使用 int
以外的任何东西(例如 FooGetterGetter.Get< double>();
)你会得到一个异常:
'MyNamespace.FooGetter'to type'MyNamespace.IFoo`1 [System.Double]'。
我不确定是为什么编译器不会为非密封版本生成错误。你的子类 FooGetter
如何让 new FooGetter()
给你任何实现 IFoo< {something_other_than_int}>
?
更新:
$ b b
根据 Dan Bryant 和 Andras Zoltan 有一些方法从构造函数返回一个派生类(或者更确切地说,为了通过分析属性返回一个不同的类型)。所以技术上这是可行的,如果类是不密封。
I have a situation where I'd like the behaviour of the compiler explained. Given a little code:
interface IFoo<T>
{
T Get();
}
class FooGetter : IFoo<int>
{
public int Get()
{
return 42;
}
}
The following compiles and runs:
static class FooGetterGetter
{
public static IFoo<T> Get<T>()
{
return (IFoo<T>)new FooGetter();
}
}
If we make a change to the signature of the Foo
class and add the sealed
keyword:
sealed class FooGetter : IFoo<int> // etc
Then I get a compiler error on the following line:
return (IFoo<T>)new FooGetter();
Of:
Cannot convert type 'MyNamespace.FooGetter' to 'MyNamespace.IFoo<T>'
Can someone explain what is happening here with regards to the sealed
keyword? This is C# 4 against a .NET 4 project in Visual Studio 2010.
Update: interestingly enough I stumbled on that part of the behaviour when I was wondering why the following code fixes it when sealed
is applied:
return (IFoo<T>)(IFoo<int>)new FooGetter();
Update: just for clarification, it all runs fine when the type of T
requested is the same as the type of T
used by the concrete type. If the types differ, the cast fails at runtime with something like:
Unable to cast object of type 'MyNamespace.StringFoo' to type 'MyNamespace.IFoo`1[System.Int32]'
In the above example, StringFoo : IFoo<string>
and the caller asks to get an int
.
Because FooGetter
is an explicit implementation of IFoo<int>
instead of implementing IFoo<T>
generically. Since it is sealed, the compiler knows there's no way to cast it to a generic IFoo<T>
if T
is anything other than an int
. If it were not sealed, the compiler would allow it to compile and throw an exception at runtime if T
was not an int
.
If you try to use it with anything other than an int
(e.g. FooGetterGetter.Get<double>();
) you get an exception:
Unable to cast object of type 'MyNamespace.FooGetter' to type 'MyNamespace.IFoo`1[System.Double]'.
What I'm not sure of is why the compiler does not generate an error for the non-sealed version. How could your sub-class FooGetter
such that new FooGetter()
give you anything that implements IFoo<{something_other_than_int}>
?
Update:
Per Dan Bryant and Andras Zoltan there are methods to return a derived class from a constructor (or possibly more precisely for the compiler to return a different type by analyzing attributes). So technically this is feasible if the class is not sealed.
这篇关于密封关键字影响编译器对转换的意见的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!