如何在通用约束类中使用方法隐藏(新)

问题描述:

我有一个容器类,它具有受限于某些基类的泛型参数。提供给泛型的类型是基类约束的子类。子类使用方法隐藏(新)来改变方法从基类的行为(不,我不能让它变成虚拟的,因为它不是我的代码)。我的问题是'new'方法没有被调用,编译器似乎认为提供的类型是基类,而不是sub,就好像我已经把它转换为基类。如何在通用约束类中使用方法隐藏(新)

很明显,我误解了一些根本性的东西。我认为通用where T: xxx是一个约束,而不是一个upcast类型。

此示例代码基本上演示了我在说什么。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace GenericPartialTest 
{ 
    class ContextBase 
    { 
     public string GetValue() 
     { 
      return "I am Context Base: " + this.GetType().Name; 
     } 

     public string GetOtherValue() 
     { 
      return "I am Context Base: " + this.GetType().Name; 
     } 

    } 

    partial class ContextSub : ContextBase 
    { 
     public new string GetValue() 
     { 
      return "I am Context Sub: " + this.GetType().Name; 
     } 
    } 

    partial class ContextSub 
    { 
     public new string GetOtherValue() 
     { 
      return "I am Context Sub: " + this.GetType().Name; 
     } 
    } 

    class Container<T> where T: ContextBase, new() 
    { 
     private T _context = new T(); 

     public string GetValue() 
     { 
      return this._context.GetValue(); 
     } 

     public string GetOtherValue() 
     { 
      return this._context.GetOtherValue(); 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      Console.WriteLine("Simple"); 
      ContextBase myBase = new ContextBase(); 
      ContextSub mySub = new ContextSub(); 

      Console.WriteLine(myBase.GetValue()); 
      Console.WriteLine(myBase.GetOtherValue()); 
      Console.WriteLine(mySub.GetValue()); 
      Console.WriteLine(mySub.GetOtherValue()); 

      Console.WriteLine("Generic Container"); 
      Container<ContextBase> myContainerBase = new Container<ContextBase>(); 
      Container<ContextSub> myContainerSub = new Container<ContextSub>(); 

      Console.WriteLine(myContainerBase.GetValue()); 
      Console.WriteLine(myContainerBase.GetOtherValue()); 
      Console.WriteLine(myContainerSub.GetValue()); 
      Console.WriteLine(myContainerSub.GetOtherValue()); 


      Console.ReadKey(); 
     } 
    } 
} 

编辑:

我想我的困惑来自于一个能做到这一点

class SomeClass<T> where T: AnotherType, new() 
{ 
    T foo = new T();  
} 

而且我预计TT即使我明白,编译器会认为T为有AnotherType的界面。我认为即使T的界面是在编译时设置的,运行时也会发生T的打字。该T foo声明似乎误导这里,因为它是真正做

AnotherType foo = new T(); 

一旦我明白,这是不是真的宣布fooT型,这是可以理解为什么new方法隐藏是行不通的。我不得不说这些。

+0

可能的重复http://*.com/questions/774726/generics-accessing-new-members-not-hidden-members – 2010-04-15 22:59:38

声明为new的方法与基类中具有相同名称/签名的方法没有关系(从编译器的角度来看)。这只是编译器的方法,它允许您在派生类中定义不同的方法,这些方法与基类级联中的方法共享一个签名。

现在,就您的具体情况而言,请注意泛型必须编译为一组字节码,而不考虑通用参数提供的类型。因此,编译器只知道在泛型类型T上定义的方法和属性 - 这是您在泛型约束中指定的基类型。编译器对衍生类型中的new方法一无所知,即使您创建了派生类型作为参数的泛型类型的实例。因此,泛型类中的调用将始终转到基类型的方法。

关于新/虚拟/覆盖有很多混淆;look at this SO question - 贾森和埃里克的回答非常好。 Jon Skeet's answer也可能帮助你理解为什么你的实现行为如此。

有你来解决此问题的两种可能的方式:

  1. 在泛型类执行条件铸(根据运行时类型信息),以派生类型(或接口)。这破坏了封装并增加了不希望的耦合。如果执行得不好,它也很脆弱。
  2. 定义您在通用约束中使用的接口,该接口公开您所关心的方法。如果你所得到的代码不是你可以改变的,这可能是不可能的。
+0

谢谢,我想我现在明白了。 – ongle 2010-04-16 00:03:28

我认为this SO question我问了可能会帮助你。请看Jon Skeet在那里的答案,为什么这是不可能的。

+0

是的,谢谢。我认为这是更多的运行时间,但我想我错了。 – ongle 2010-04-15 23:57:40

添加另一个图层 - 从您的第三方类继承您的泛型,而不是继承自第三方的新类。在这个新班级中,您可以将所讨论的方法定义为新的虚拟班级。如果所有的代码都不会直接引用第三方的类,它应该可以工作

+0

谢谢,是的,我知道一些解决问题的方法。我只是想了解核心问题,所以我不会再犯这个错误。 – ongle 2010-04-16 00:01:32