这有点冗长,所以这里是快速版本:
为什么这会导致运行时 TypeLoadException?(编译器应该阻止我这样做吗?)
interface I
{
void Foo<T>();
}
class C<T1>
{
public void Foo<T2>() where T2 : T1 { }
}
class D : C<System.Object>, I { }
如果您尝试实例化 D,则会发生异常。
更长,更具探索性的版本:
考虑:
interface I
{
void Foo<T>();
}
class C<T1>
{
public void Foo<T2>() where T2 : T1 { }
}
class some_other_class { }
class D : C<some_other_class>, I { } // compiler error CS0425
这是非法的,因为 上的类型约束与 上的C.Foo()
不匹配I.Foo()
。它会生成编译器错误 CS0425。
但我想我也许可以打破规则:
class D : C<System.Object>, I { } // yep, it compiles
通过Object
用作 T2 上的约束,我否定了该约束。我可以安全地将任何类型传递给D.Foo<T>()
,因为一切都源自Object
.
即便如此,我仍然希望得到一个编译器错误。在 C#语言的意义上,它违反了“C.Foo() 上的约束必须与 I.Foo() 上的约束相匹配”的规则,我认为编译器会严格遵守这些规则。但它确实编译。似乎编译器看到了我在做什么,理解它是安全的,并且视而不见。
我以为我已经侥幸逃脱了,但运行时说没那么快。如果我尝试创建 的实例D
,则会收到 TypeLoadException:“类型 'D' 上的方法 'C`1.Foo' 试图隐式实现具有较弱类型参数约束的接口方法。”
但是这个错误在技术上不是错误的吗?不使用Object
forC<T1>
否定对 的约束C.Foo()
,从而使其等效于 - NOT 强于 - I.Foo()
?编译器似乎同意,但运行时不同意。
为了证明我的观点,我通过去掉D
等式来简化它:
interface I<T1>
{
void Foo<T2>() where T2 : T1;
}
class some_other_class { }
class C : I<some_other_class> // compiler error CS0425
{
public void Foo<T>() { }
}
但:
class C : I<Object> // compiles
{
public void Foo<T>() { }
}
这对于传递给Foo<T>()
.
为什么?运行时是否存在错误,或者(更有可能)我没有看到导致此异常的原因 - 在这种情况下,编译器不应该阻止我吗?
有趣的是,如果通过将约束从类移动到接口来反转场景......
interface I<T1>
{
void Foo<T2>() where T2 : T1;
}
class C
{
public void Foo<T>() { }
}
class some_other_class { }
class D : C, I<some_other_class> { } // compiler error CS0425, as expected
我再次否定了约束:
class D : C, I<System.Object> { } // compiles
这次运行正常!
D d := new D();
d.Foo<Int32>();
d.Foo<String>();
d.Foo<Enum>();
d.Foo<IAppDomainSetup>();
d.Foo<InvalidCastException>();
任何事情都会发生,这对我来说很有意义。D
(在等式中有或没有相同)
那么为什么第一种方式会中断?
附录:
我忘了补充一点,TypeLoadException 有一个简单的解决方法:
interface I
{
void Foo<T>();
}
class C<T1>
{
public void Foo<T2>() where T2 : T1 { }
}
class D : C<Object>, I
{
void I.Foo<T>()
{
Foo<T>();
}
}
明确实施I.Foo()
是好的。只有隐式实现会导致 TypeLoadException。现在我可以这样做了:
I d = new D();
d.Foo<any_type_i_like>();
但这仍然是一个特例。尝试使用 System.Object 以外的任何其他内容,这将无法编译。我觉得这样做有点脏,因为我不确定它是否故意这样工作。