正确使用C#';新';使受保护的财产公开的修饰符

本文关键字:财产 受保护 | 更新日期: 2023-09-27 18:28:54

假设我有一个抽象基类

public abstract class BaseClass
{
    private MyObject myObject;
    protected MyObject PropA
    {
        get
        {
            if(myObject == null) this.myObject = new MyObject();
            return this.myObject;
        }
    }
}

并且在我的一个派生的类中,我想使受保护的基类属性PropA公开。在这种情况下使用new修饰符是否正确?

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

正确使用C#';新';使受保护的财产公开的修饰符

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

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

对我来说,使用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<T>.Add就只是另一个"通用"公共方法。由于MyList<T>继承了List<T>MyList<T>.Add"隐藏"了List<T>.Add,因为两种方法的名称和参数相同。

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

当然,它可能会导致逻辑错误和类API的不正确使用。

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

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

如果要在派生类中添加与基类中成员同名的成员,则new关键字有效且正确;然而,这种设计似乎违背了抽象类的目的。使PropA在基类中公开和虚拟或公开和抽象:

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. 
}
这是正确的。任何时候,如果类的成员与继承类中的成员同名,则需要使用new关键字(即使这两个属性/方法的返回类型不同)。

我建议你也许是

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

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