【问题标题】:Generics: Accessing New Members, Not Hidden Members泛型:访问新成员,而不是隐藏成员
【发布时间】:2009-04-21 21:33:21
【问题描述】:

我遇到了泛型和新成员的问题。我编写了一个对 ObjectA 类型的对象进行操作的泛型类。 ObjectB 派生自 ObjectA 并隐藏了一些 ObjectA 的成员。当我将 ObjectB 的类型作为类型参数提供给泛型类时,我希望当我调用任何被 ObjectB 隐藏的成员时,我会调用 ObjectB 的实现。但是,CLR 仍然调用隐藏成员(ObjectA 的实现)。这似乎不合逻辑,因为我明确地将 ObjectB 的类型提供给了泛型类。这是泛型本身的问题,还是我做错了什么?

编辑:不幸的是,我无权访问 ObjectA 的源代码,并且我想要覆盖的成员不是虚拟的。如果我可以访问 ObjectA 的源代码,我会将成员设为虚拟,但由于我不能这样做,我唯一的“覆盖”成员的选择是通过“new”关键字。

class GenericClass<T> where T : ObjectA  
{  
    public void DoWork(T item)  
    {  
        // When type parameter 'T' is ObjectB, should get ObjectB's implementation  
        item.Invoke();  
    }  
}  

class ObjectA  
{
    public void Invoke()  
    {  
        // A's implementation...  
    }  
}

class ObjectB : ObjectA  
{
    public new void Invoke()  
    {  
        // B's implementation...  
    }  
}

static void Main()  
{  
    GenericClass<ObjectB> genericClass = new GenericClass<ObjectB>();  
    ObjectB objectB = new ObjectB();  
    genericClass.DoWork(objectB);  
}

【问题讨论】:

    标签: .net generics


    【解决方案1】:

    没有。编译器生成的调用是针对它在编译时知道的成员。那是ObjectA暴露的成员。

    您有什么原因不使用普通继承,使用虚拟/覆盖方法?

    顺便说一下,这里有另一个相同类型的例子 - 不使用重载的 == 字符串运算符,即使在对 Foo 的调用中 Tstring

    using System;
    
    class Test
    {
        static bool Foo<T>(T first, T second)
            where T : class
        {
            return first == second;
        }
    
        static void Main()
        {
            string x = "hello";
            string y = new string(x.ToCharArray());
    
            Console.WriteLine(Foo(x, y));
        }
    }
    

    【讨论】:

    • 感谢您的回答。我会使用虚拟/覆盖方法,但我从 System.Windows.Form 继承并尝试为非虚拟成员编写自己的实现。
    • 那你就不能这样访问了。听起来你正试图让它“几乎是虚拟的”——它不是那样工作的。
    • 嗯。如果您习惯于 C++ 模板,我同意这有点不直观。 C#做模板类的单独编译,当时只知道ObjectA。当模板被实例化时,实例化的类不会用ObjectB的附加知识重新编译。
    【解决方案2】:

    这可能不是您问题的答案,但我看不出您的方法有什么意义(可能是因为我只看到了一个简化的示例)。

    我建议使用以下方法:

    class ObjectA
    {
        public virtual void Invoke()
        {
            // do some work
        }
    }
    
    class ObjectB : ObjectA
    {
        public override void Invoke()
        {
            // do some other work
        }
    }
    
    class GenericNotNeededClass
    {  
        public void DoWork(ObjectA item)  
        {  
            item.Invoke();  
        }  
    }  
    
    
    static void Main()  
    {  
        GenericNotNeededClass nonGenericClass = new GenericNotNeededClass();  
        ObjectB objectB = new ObjectB();  
        nonGenericClass.DoWork(objectB);
    }
    

    根据您的示例代码,我相信代码可以满足您的需求。

    【讨论】:

      【解决方案3】:

      您将 T 定义为您的泛型的 ObjectA 类型。如果 Invoke() 是虚拟的,它会按照您的想法工作,但因为不是,所以您的泛型调用 ObjectA 实现,因为这是 T 定义的。

      没有虚拟方法表条目指向 Invoke() 的 ObjectB 实现,因此这是运行时可以调用的所有内容。如果它是一个虚拟方法,那么 VMT 中就会有一个方法地址,并且它的行为就像您认为的那样。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-10
        • 1970-01-01
        相关资源
        最近更新 更多