【问题标题】:Make base class method use new child field使基类方法使用新的子字段
【发布时间】:2023-03-30 01:00:01
【问题描述】:

我有一个类,它调用一个对象的方法,该对象隐藏在继承它的类中(但新字段也是从 baseField 继承的),我需要调用此方法新字段,但是当我调用 childClass.doSomething() 时,我收到一个异常,说 baseField 为空。

我认为这是因为 baseClass 中的 baseField 正在被访问,尚未实例化但我不确定

当从 childClass 访问时,我怎样才能让 someMethod 使用 ExtendedBaseField

public abstract class baseClass{

    protected BaseField baseField;

    public void someMethod(){
        baseField.doSomething()
    }
}

还有一个继承它的类:

public class childClass : baseClass{
    protected new ExtendedBaseField baseField = new ExtendedBaseField();
}

new childClass().someMethod(); //null pointer exception

ExtendedBaseField 继承 BaseField

【问题讨论】:

  • protected new ExtendedBaseField baseField 是什么意思?
  • @farukdgn 如果你的意思是类型前的 new 关键字,它是告诉编译器你隐藏了继承类中的字段

标签: c# inheritance polymorphism


【解决方案1】:

您正在使用 new 关键字创建一个新字段,而不是设置旧字段。我反对保护字段,它们应该是属性。你也应该骆驼大小写 .NET 中的所有属性、方法和类。括号也应该单独一行。

根据您的 cmets,您希望对新类型进行类型访问,因此您应该使您的基类通用。我也证明了这一点。

public abstract class BaseClass<T>
    where T: BaseField
{
    protected BaseClass(T baseField)
    {
         this.BaseField = baseField;
    }
    protected T BaseField{get; private set;};

   public void SomeMethod()
   {
    BaseField.DoSomething()
   }
}
public class ChildClass : BaseClass<ExtendedBaseField>
{
      public ChildClass() : base(new ExtendedBaseField())
      {

      }
}

【讨论】:

  • 我需要访问childClass中ExtendedBaseField中的方法。是的 - 我的类名不好,只是在这里输入了它,这不是我的实际代码 - 为了简洁起见,我有这种方式的括号......为什么受保护的字段应该是属性?我只使用公共成员的属性而不是访问者
  • @mbdavis 好吧,您刚刚在这里看到了一个很好的理由,我将其设为 BaseField protected get but private set,因此它只能由基类设置。如果您想在 getter/setter 中实现更多逻辑,它还可以进行更好的重构。
【解决方案2】:

其他人给出了正确的技术答案:您明确地将字段隐藏在基类中。

我将在这里谈谈不好的做法。

在 C++ 中,有 RAII 的概念。资源分配是初始化。在 C# 中,我们通常不必像在 C++ 中那样考虑资源分配,但 RAII 的模式仍然是一个很好的做法。

类中声明的所有字段都应内联初始化

protected BaseField baseField = new BaseField();

...或在该类的构造函数中

protected BaseField baseField;
public BaseClass<T>()
{
    this.baseField = new BaseField();
}

如果不可能,则使用抽象属性而不是字段,这会强制子类实现并初始化它。

protected abstract BaseField BaseField { get; }

【讨论】:

    【解决方案3】:

    子类隐藏 baseField:

    protected new ExtendedBaseField baseField = new ExtendedBaseField();
    

    这会创建一个newbaseField 属性,因此子类无法再看到基类的baseField 属性。因此,它永远不会设置。因此,它是null

    不要隐藏基类的字段。如果您希望基类使用它,请让子类使用它:

    public class childClass : baseClass {
        public childClass() {
            baseField = new ExtendedBaseField();
        }
    }
    

    【讨论】:

    • 但是当我希望它使用 ExtendedBaseField 中的方法时,我的 childClass 会将 baseField 视为 BaseField ...这意味着我每次想使用 ExtendedBaseField 方法时都必须转换 baseField,是最好的方法?
    • @mbdavis:我不知道你想要完成什么,所以我真的不能建议什么是“最好的方法”。但这听起来确实违反了 Liskov 替换原则。继承模型可能不是从这里开始的正确方法。
    • 我会支持@David 所说的。您可能想要做的是在 BaseClass 调用 DoSomething() 上定义一个抽象方法。 ChildClass 然后将通过调用extendedBaseField.DoSomething() 来实现该方法。 BaseClass 甚至根本没有 baseField。
    猜你喜欢
    • 1970-01-01
    • 2013-02-26
    • 1970-01-01
    • 1970-01-01
    • 2011-01-22
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 2018-10-15
    相关资源
    最近更新 更多