【问题标题】:hiding non-generic base class property in a generic class在泛型类中隐藏非泛型基类属性
【发布时间】:2013-03-05 00:44:32
【问题描述】:

在泛型类中隐藏非泛型基类属性或方法的标准模式是什么?

我有 2 个解决方案,实际上是采用相同但不同的方法。解决方案一使用更多内存,因为基类和派生类引用相同的对象,解决方案二由于强制转换而更慢。(或者我错了?)

基类:

public class MyDataBase {}

public class MyDataDerived : MyDataBase {}

 public class BaseFoo
 {
     private readonly MyDataBase _data;
     public MyDataBase Data { get { return _data; } }

     public BaseFoo(MyDataBase data) {
      _data = data;
  }
}

解决方案 1:

public class GenericFooWithHiding<T> : BaseFoo where T : MyDataBase
{
     private readonly T _data;

     public GenericFooWithHiding(T data) : base(data) { _data = data; }

     public new T Data { get { return _data; } }
 }

解决方案 2:

public class GenericFooWithCasting<T> : BaseFoo where T : MyDataBase
{
     public GenericFooWithCasting(T data) : base(data) {}

     public new T Data { get { return base.Data as T; } }
}

【问题讨论】:

  • 你能解释一下为什么在这里有泛型的目的吗?在 T 只能是一种类型的情况下,您可以使用 MyDataBase 类型并仍然将 MyDataBaseDerived 发送到构造函数。
  • @InfinitePossiblities: T 可以是从MyDataBase 派生的任何类型。问题是如何将属性的返回类型改为T
  • @pescolino 现在说得通了,谢谢!

标签: c# generics inheritance return-type


【解决方案1】:

如果我要从这两种方法中进行选择,我会选择第二种(演员)方法:将相同的数据存储在多个地方几乎可以保证使它们不同步。因此,如果性能很重要,我会考虑铸造成本(不太可能是重要的) - 衡量和验证。

旁注:我会尽量避免使用new 属性,因为这会导致混淆,具体取决于您拥有的变量类型。使基类的Data 属性受保护可能是特定示例中的潜在解决方案。

【讨论】:

    【解决方案2】:

    解决方案 3

    颠倒BaseFooGenericFoo&lt;T&gt;之间的继承关系,这样泛型的使用就变得有意义了,根本不需要隐藏。

    public class MyDataBase {
    }
    
    public class MyDataDerived: MyDataBase {
    }
    
    public class GenericFoo<T> where T: MyDataBase {
        public GenericFoo(T data=default(T)) {
        }
    
        public T Data {
            get {
                return _data;
            }
        }
    
        protected readonly T _data;
    }
    
    public class DerivedFoo: GenericFoo<MyDataDerived> {
        public DerivedFoo(MyDataDerived data=default(MyDataDerived))
            : base(data) {
        }
    }
    
    public class BaseFoo: GenericFoo<MyDataBase> {
        public BaseFoo(MyDataBase data=default(MyDataBase))
            : base(data) {
        }
    }
    

    【讨论】:

      【解决方案3】:

      我假设您不能更改类型 BaseFoo,否则您可以首先使其成为通用类型。

      我不会使用new 来更改返回类型,因为这可能会让人感到困惑。例如:这段代码sn-p中data的类型是什么?

      GenericFoo<MyDataDerived> foo = new GenericFoo<MyDataDerived>(new MyDataDerived());
      var data = ((BaseFoo)foo).Data;
      

      它是MyDataBase(呼叫转到BaseFoo)。但是,如果您在BaseFoo 中有一个虚拟属性,它在GenericFoo 中被覆盖,它将被调用?:

      public class BaseFoo
      {
          public virtual MyDataBase MoreData
          {
              get
              {
                  return _data;
              }
          }
      }
      
      public class GenericFoo<T> : BaseFoo where T : MyDataBase
      {
          public override MyDataBase MoreData
          {
              get
              {
                  return _someOtherData;
              }
          }
      }
      
      // which property is called?
      var data = ((BaseFoo)foo).MoreData;
      

      这次呼叫转到GenericFoo。由于这通常是预期的行为,我建议不要使用new

      我会在GenericFoo 中实现一个方法来避免使用new(我会使用演员表):

      public class GenericFoo<T> : BaseFoo
          where T : MyDataBase
      {
          public T GetData()
          {
              return (T)base.Data;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2011-10-08
        • 1970-01-01
        • 1970-01-01
        • 2019-08-12
        • 1970-01-01
        • 2023-03-28
        • 2017-12-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多