如何C#泛型实现的? [英] How are C# Generics implemented?

查看:171
本文介绍了如何C#泛型实现的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我原以为泛型在C#中实现这样一个新的类/方法/什么具备的,你生成,无论是在运行时或编译时,当使用一个新的泛型类型,类似于C ++模板(这是我从来没有真正看着,我很可能是错的,对此我很乐意接受校正)。

I had thought that Generics in C# were implemented such that a new class/method/what-have-you was generated, either at run-time or compile-time, when a new generic type was used, similar to C++ templates (which I've never actually looked into and I very well could be wrong, about which I'd gladly accept correction).

但在我的编码,我想出了一个确切的反例:

But in my coding I came up with an exact counterexample:

static class Program {
    static void Main()
    {
        Test testVar = new Test();

        GenericTest<Test> genericTest = new GenericTest<Test>();
        int gen = genericTest.Get(testVar);

        RegularTest regTest = new RegularTest();
        int reg = regTest.Get(testVar);

        if (gen == ((object)testVar).GetHashCode())
        {
            Console.WriteLine("Got Object's hashcode from GenericTest!");
        }
        if (reg == testVar.GetHashCode())
        {
            Console.WriteLine("Got Test's hashcode from RegularTest!");
        }
    }

    class Test
    {
        public new int GetHashCode()
        {
            return 0;
        }
    }

    class GenericTest<T>
    {
        public int Get(T obj)
        {
            return obj.GetHashCode();
        }
    }

    class RegularTest
    {
        public int Get(Test obj)
        {
            return obj.GetHashCode();
        }
    }
}



这两项控制台行打印

Both of those console lines print.

我知道,发生这种情况的实际原因是,为了Object.GetHashCode()的虚拟呼叫无法解析为Test.GetHashCode(),因为在测试方法标记为新的,而不是覆盖。因此,我知道如果我使用了重写,而不是新上Test.GetHashCode()则返回0将多态覆盖对象的方法GetHashCode,这不会是真实的,但根据我(以前)的理解C#泛型不会也无妨,因为的T每个实例都已经换成了测试,因而方法调用将有静态(或通用的解决时间)被解析为新的方法。

I know that the actual reason this happens is that the virtual call to Object.GetHashCode() doesn't resolve to Test.GetHashCode() because the method in Test is marked as new rather than override. Therefore, I know if I used "override" rather than "new" on Test.GetHashCode() then the return of 0 would polymorphically override the method GetHashCode in object and this wouldn't be true, but according to my (previous) understanding of C# generics it wouldn't have mattered because every instance of T would have been replaced with Test, and thus the method call would have statically (or at generic resolution time) been resolved to the "new" method.

所以我的问题是这样的:如何被仿制药在C#中实施我不知道CIL字节码,但我知道Java字节码,所以我知道如何对象 - ?面向CLI语言在较低水平运行。随意在这一水平来解释。

So my question is this: How are generics implemented in C#? I don't know CIL bytecode, but I do know Java bytecode so I understand how Object-oriented CLI languages work at a low level. Feel free to explain at that level.

顺便说一句,我认为C#泛型实施了,那是因为大家总是在C#中调用通用系统真正的泛型,相比,到Java的类型擦除系统

As an aside, I thought C# generics were implemented that way because everyone always calls the generic system in C# "True Generics," compared to the type-erasure system of Java.

推荐答案

GenericTest< T>获得(T) 的C#编译器的的拿起了 object.GetHashCode 应该叫(几乎)。没有办法,这将解决以新的GetHashCode 方法在运行时(这将有自己的插槽中的方法表,而不是覆盖插槽 object.GetHashCode )。

In GenericTest<T>.Get(T), the C# compiler has already picked that object.GetHashCode should be called (virtually). There's no way this will resolve to the "new" GetHashCode method at runtime (which will have its own slot in the method-table, rather than overriding the slot for object.GetHashCode).

从埃里克利珀的的有什么区别,第一部分:泛型不是模板,这个问题解释(用来设置略有不同,但教训很好的转化为您的方案):

From Eric Lippert's What's the difference, part one: Generics are not templates, the issue is explained (the setup used is slightly different, but the lessons translate well to your scenario):

这说明,在C#泛型不像模板C ++。
你可以把模板作为一个奇特的裤子搜索和替换
机制[...]这是类型也不怎么通用工作。泛型类型是,
哦,通用的。我们做重载决议的一次并烘烤在
的结果。 [...]我们为泛型类型生成的IL已经
的方法,它会调用挑出来。抖动不说
好,我碰巧知道,如果我们让C#编译器这个额外的信息,以执行
现在那么就选择了一个
不同的超载。让我改写生成的代码忽略最初生成C#编译器的
码......抖动知道C#的规则
罢了。

This illustrates that generics in C# are not like templates in C++. You can think of templates as a fancy-pants search-and-replace mechanism.[...] That’s not how generic types work; generic types are, well, generic. We do the overload resolution once and bake in the result. [...] The IL we’ve generated for the generic type already has the method its going to call picked out. The jitter does not say "well, I happen to know that if we asked the C# compiler to execute right now with this additional information then it would have picked a different overload. Let me rewrite the generated code to ignore the code that the C# compiler originally generated..." The jitter knows nothing about the rules of C#.

和您所需的语义解决方法:

And a workaround for your desired semantics:

现在,如果你想重载决议在基于运行时类型
的参数运行时被重新执行,我们能为你做的;这就是新的动态
功能确实在C#4.0。只需更换物与动态,当
你让涉及该对象的一个​​电话,我们将运行在运行时,过载
解析算法,动态地吐调用
的方法代码编译器会回升,如果它在编译时已知的所有的
运行时类型。

Now, if you do want overload resolution to be re-executed at runtime based on the runtime types of the arguments, we can do that for you; that’s what the new "dynamic" feature does in C# 4.0. Just replace "object" with "dynamic" and when you make a call involving that object, we’ll run the overload resolution algorithm at runtime and dynamically spit code that calls the method that the compiler would have picked, had it known all the runtime types at compile time.

这篇关于如何C#泛型实现的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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