为什么会出现这种情况仿制药导致TypeLoadException? [英] Why does this generics scenario cause a TypeLoadException?

查看:176
本文介绍了为什么会出现这种情况仿制药导致TypeLoadException?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这变得有点啰嗦,所以这里的快速版本:

This got a bit long-winded, so here's the quick version:

为什么这会导致运行时TypeLoadException (而且应该编译器阻止了我这样做)

Why does this cause a runtime TypeLoadException? (And should the compiler prevent me from doing it?)

interface I
{
    void Foo<T>();
}

class C<T1>
{
    public void Foo<T2>() where T2 : T1 { }
}

class D : C<System.Object>, I { } 

如果您尝试实例ð发生异常。

The exception occurs if you try to instantiate 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

This is illegal because the type constraints on C.Foo() don't match those on I.Foo(). It generates compiler error CS0425.

不过,我想我也许能打破规则:

But I thought I might be able to break the rule:

class D : C<System.Object>, I { } // yep, it compiles

通过使用对象作为T2的限制,我的否定的该约束。我可以在任何类型的安全传递给 D.Foo< T>(),因为一切从派生对象

By using Object as the constraint on T2, I'm negating that constraint. I can safely pass any type to D.Foo<T>(), because everything derives from Object.

即便如此,我仍有望得到一个编译错误。在C#的语言的意义上说,它违反了规则,对C.Foo(约束)必须在I.Foo()的约束匹配,我想,编译器将是一个坚持己见的人规则。但它确实编译。这似乎编译器看到我在做什么,领会它的安全,熟视无睹。

Even so, I still expected to get a compiler error. In a C# language sense, it violates the rule that "the constraints on C.Foo() must match the constraints on I.Foo()", and I thought the compiler would be a stickler for the rules. But it does compile. It seems the compiler sees what I'm doing, comprehends that it's safe, and turns a blind eye.

我想我会侥幸成功,但运行时说的不会这么快的。如果我尝试创建 D 的一个实例,我得到一个TypeLoadException:方法上键入'D''C`1.Foo尝试隐式实现与接口的方法弱类型参数约束。

I thought I'd gotten away with it, but the runtime says not so fast. If I try to create an instance of D, I get a TypeLoadException: "Method 'C`1.Foo' on type 'D' tried to implicitly implement an interface method with weaker type parameter constraints."

但不是错误技术上的错误?不使用对象 C< T1> 否定关于约束C.Foo( ),从而使其等同于 - 不超过强 - I.Foo()?编译器似乎都同意,但运行时没有。

But isn't that error technically wrong? Doesn't using Object for C<T1> negate the constraint on C.Foo(), thereby making it equivalent to - NOT stronger than - I.Foo()? The compiler seems to agree, but the runtime doesn't.

要证明我的观点,我通过采取简化IT D 的方程:

To prove my point, I simplified it by taking D out of the equation:

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>() { }
}

不过:<​​/ p>

But:

class C : I<Object> // compiles
{
    public void Foo<T>() { }
}

这编译和完美的运行任何类型的传递给美孚< T>()

This compiles and runs perfectly for any type passed to Foo<T>().

为什么呢?有没有在运行时,或者更有可能的一个bug是否有此异常,我没有看到一个原因 - 在这种情况下不应该编译器停在我身上。

Why? Is there a bug in the runtime, or (more likely) is there a reason for this exception that I'm not seeing - in which case shouldn't the compiler have stopped me?

有趣的是,如果该场景是通过从类约束移动到接口.​​..

Interestingly, if the scenario is reversed by moving the constraint from the class to the interface...

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



我又否定了约束:

And again I negate the constraint:

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 公式中)

那么,为什么第一种方式打破?

So why does the first way break?

附录:

我忘了补充一点,对于TypeLoadException一个简单的解决方法:

I forgot to add that there is a simple workaround for the 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。现在我可以这样做:

Explicitly implementing I.Foo() is fine. Only the implicit implementation causes the TypeLoadException. Now I can do this:

        I d = new D();
        d.Foo<any_type_i_like>();



但它仍然是一个特例。尝试使用别的以外System.Object的,这将无法编译。我觉得有点脏这样做,因为我不知道这是否故意以这种方式工作。

But it's still a special case. Try using anything else other than System.Object, and this won't compile. I feel a bit dirty doing this because I'm not sure if it intentionally works this way.

推荐答案

这是一个错误 - 看实现泛型方法从通用接口引起TypeLoadException 并的无法验证的代码具有通用接口和泛型方法与类型参数约束。 。这不是我清楚它是否是一个C#错误或CLR错误,虽然

It's a bug - see Implementing Generic Method From Generic Interface Causes TypeLoadException and Unverifiable Code with Generic Interface and Generic Method with Type Parameter Constraint. It's not clear to me whether it's a C# bug or a CLR bug, though.

[由OP补充:]

下面是微软所说的在第二个线程您链接到(我的重点):

Here's what Microsoft says in the second thread you linked to (my emphasis):

有是$ b $之间的不匹配运行时和
C#编译器所使用b算法来确定一组
的限制是另一个
组强。在C#
编译器接受一些构建
的运行时拒绝和
结果。这不匹配的结果是TypeLoadException你
请参阅。我们正在研究以确定
如果这个代码是
这一问题的一种表现。无论如何,
肯定不是通过设计的
编译器接受这样的
运行时异常的
的结果。

There is a mismatch between the algorithms used by the runtime and the C# compiler to determine if one set of constraints is as strong as another set. This mismatch results in the C# compiler accepting some constructs that the runtime rejects and the result is the TypeLoadException you see. We are investigating to determine if this code is a manifestation of that problem. Regardless, it is certainly not "By Design" that the compiler accepts code like this that results in a runtime exception.

问候,

埃德毛雷尔C#编译器开发

Ed Maurer C# Compiler Development Lead

这是我加粗部分,我觉得他的说法,这是一个编译器错误。这是早在2007年我想这不是严重到足以成为一个优先为他们解决它。

From the part I bolded, I think he's saying this is a compiler bug. That was back in 2007. I guess it's not serious enough to be a priority for them to fix it.

这篇关于为什么会出现这种情况仿制药导致TypeLoadException?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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