代码之家  ›  专栏  ›  技术社区  ›  Stefan Steinegger

使用成员隐藏(`new`)来获得更具体的返回类型

  •  3
  • Stefan Steinegger  · 技术社区  · 15 年前

    我正在考虑使用 new

    要解决的问题是当存在多个“镜像”类层次结构时,其中每个层次结构层的类型都引用另一个层次结构的同一级别。这很难解释,所以举个例子:

    class A1 {}
    class A2 : A1 {}
    class A3 : A2 {}
    
    abstract class B1
    {
      protected A1 myA;
    
      A1 MyA { get { return myA; } }
    }
    
    abstract class B2 : B1
    {
      new A2 MyA { get { return (A2)myA; } }
    }
    
    class B3 : B2
    {
      new A3 MyA 
      { 
        get { return (A3)myA; } 
        set { myA = value; }
      }
    }
    

    有些代码只处理抽象的“级别”1( A1 / B1 等等),其他级别也一样。如果每个“级别”都能看到尽可能具体的类型,那就太好了。目前,我在最顶层定义了类型,并一直在调用代码中向下转换。有时,我使用另一个名称为某个“级别”添加另一个成员,这会导致更多冗余成员。我想把它弄干净。

    (这里没有泛型,因为 B2 不知道也没用 B3 (它需要额外的接口)。如果有很多类型(例如C1/2/3,D1/2/3…),就会有太多的泛型参数。从技术上讲,这是可行的,但只是变得非常复杂。)

    另外,我将序列化其中一些类( DataContractSerializer )一些将被映射到一个数据库使用NHibernate。

    有人已经做过这样的事了吗?是否值得推荐?有没有其他方法可以解决同样的问题?

    :由于讨论了强制转换和属性的实现,我稍微更改了代码。这实际上不是问题所在。我只想写尽可能少的代码来做一个简短的例子。

    2 回复  |  直到 15 年前
        1
  •  2
  •   Ben Voigt    15 年前

    IEnumerable 是这种模式最常见的例子。

        2
  •  2
  •   Jaroslav Jandek    15 年前

    我会的

    这只是为了省去打字,它会降低你的性能,因为 B3.MyA 基本上可以 return (A3)(A2)this.MyA; b3.MyA as A3 仅在必要时直接使用。

    如果你忘记初始化 MyA 在里面 B3 类型的对象 A3 ,您的强制转换将失败,因为它将是类型的对象 A1 A2 或者别的什么。你可以很容易地射中自己的腿。

    编辑 一种打字安全的方法 将。您可以将这样做的风险降到最低(例如您编辑的代码显示),但可能性仍然存在。然而,这种结构的好处并不能证明危险是正当的。

    编辑2 :注意 Technically it would work, but it just gets very complicated.

    没那么复杂。作为比较:

    public abstract class B1<TA, TC> where TA: A1 where TC: A1
    {
        public TA MyA { get; protected set; }
        public TC MyC { get; protected set; }
    }
    
    public abstract class B2<TA, TC> : B1<TA, TC> where TA : A2 where TC : A2
    {
    }
    
    public class B3 : B2<A3, A3>
    {
    }
    

    更少的代码,更好的安全性,记住您可以随时使用 using 如果您不喜欢输入太多:

    using ClassicB2 = MemberHiding.B2<MemberHiding.A3, MemberHiding.A3>;
    ClassicB2 b3 = new B3();