【问题标题】:Correct use of C# 'new' modifier to make protected property public正确使用 C# 'new' 修饰符使受保护的属性公开
【发布时间】:2014-11-01 22:12:37
【问题描述】:

假设我有一个抽象基类

public abstract class BaseClass
{
    private MyObject myObject;

    protected MyObject PropA
    {
        get
        {
            if(myObject == null) this.myObject = new MyObject();
            return this.myObject;
        }
    }
}

...在我的一个派生类中,我想将protected基类属性PropApublic。在这种情况下使用new modifier 是否正确?

public class DerivedClass : BaseClass
{
    public new MyObject PropA
    {
        get
        {
            return base.PropA;
        }
    }
}

【问题讨论】:

  • 这不是大错特错。为什么你不能在基类中公开它是很难猜到的。一个只有 BaseClass 引用的客户端程序员可能会给自己带来麻烦。
  • 嗯,它在技术上是正确的,但乍一看,这似乎是一个可疑的设计。如果PropA 可以在某些派生类中公开,为什么它会受到保护?为什么不一开始就公开呢?是什么让 public PropA 在其他派生类中成为糟糕的设计?

标签: c# inheritance


【解决方案1】:

在这种情况下使用 new 修饰符是否正确?

从技术上讲 - 是的,不会有错误或警告。

对我来说,使用 new 关键字本身作为修饰符表示设计缺陷。

我举一个例子。

public class MyList<T> : List<T>
{
    public int AddCallsCount;
    public new void Add(T t)
    {
        AddCallsCount++;
        base.Add(t);
    }
}

[TestClass]
public class Test
{
    [TestMethod]
    public void TestThatsNotGood()
    {
        List<object> list = new MyList<object>();
        list.Add(1);
        list.Add(2);

        MyList<object> myList = list as MyList<object>;

        Assert.AreEqual(0, myList.AddCallsCount);

    }
}

看起来多态有效,但实际上并没有。

更新: 好的,有非常简化的解释。我省略了对多态性的解释。

多态是通过实现abstract\virtualoverriding 方法实现的。只要没有指定virtualoverride 修饰符,MyList&lt;T&gt;.Add 就只是另一种“常用”公共方法。并且MyList&lt;T&gt;继承了List&lt;T&gt;MyList&lt;T&gt;.Add'隐藏'List&lt;T&gt;.Add,因为这两个方法的名称和参数是相同的。

在较低级别:只要方法AddList&lt;T&gt; 类型定义没有用virtual 关键字标记,编译器就不会搜索实际实例类型的覆盖方法(在这种情况下为MyList&lt;T&gt; ) 用于给定类型的变量(在这种情况下为List&lt;T&gt;)。

这肯定会导致逻辑错误和类 API 的错误使用。

因此,编译器“认为”可能存在逻辑错误或设计缺陷并警告程序员。 new 关键字只是与编译器对话的一种方式

是的,我知道它不好,但我需要它,因为我的设计不好

.

【讨论】:

  • 解释为什么(以及在哪里)多态性(令人惊讶地)失败会很有帮助。另外,继承自List&lt;T&gt; 可以说是not a good idea
  • @DavidRR,您可以将 List 更改为 SomeBaseClass,将 MyList 更改为 SomeDerivedClass。没关系。列表示例很自然,这是我想到的第一个示例。
【解决方案2】:

new 关键字有效且正确,如果您想在派生类中添加与基类中的成员同名的成员;然而,这种设计似乎违背了抽象类的目的。在基类中将PropA设为public和virtual或者public和abstract:

public abstract class BaseClass
{
    // Property not implemented here.
    public abstract MyObject PropA { get; }

    private MyObject _propB;
    // Property implemented, but implementation can be overridden in derived class.
    public virtual MyObject PropB
    {
        get { return _propB ?? (_propB = new MyObject()); }
    }

    public int PropC { get { return 5; } }
}

public class DerivedClass : BaseClass
{
    // You must provide an implementation here.
    private MyObject _propA;
    public override MyObject PropA
    {
        get { return _propA ?? (_propA = new MyObject()); }
    }

    // You are free to override this property and to provide an new implementation
    // or to do nothing here and to keep the original implementation.
    public override MyObject PropB
    {
        get { return <new implementation...>; }
    }

    // PropC is inherited as is and is publicly visible through DerivedClass as well. 
}

【讨论】:

    【解决方案3】:

    没错。任何时候你有一个类的成员与继承类中的成员同名时,你需要使用 new 关键字(即使两个属性/方法具有不同的返回类型)。

    【讨论】:

      【解决方案4】:

      我可能会推荐你

      public new string test { 
                                get { return (this as T).test; } 
                                set { (this as T).test = value; } 
                             }
      

      因为base 只给你父母,但如果你想走得更高,你必须投。

      【讨论】:

        猜你喜欢
        • 2013-03-05
        • 1970-01-01
        • 1970-01-01
        • 2018-10-17
        • 2019-05-07
        • 2015-11-27
        • 2014-12-29
        • 2013-04-03
        相关资源
        最近更新 更多