C# 重写子类中的字段或属性

C# 重写子类中的字段或属性,c#,properties,field,C#,Properties,Field,我有一个抽象基类,我想声明一个字段或一个属性,该字段或属性在继承自父类的每个类中具有不同的值 我想在基类中定义它,这样我就可以在基类方法中引用它-例如,重写ToString以表示“此对象的类型为property/field”。 我有三种方法,我可以看到这样做,但我想知道-什么是最好的或被接受的方式做这件事?新手问题,对不起 选项1: 使用抽象属性并在继承的类上重写它。这得益于强制执行(您必须覆盖它),而且它是干净的。但是,返回一个硬代码值而不是封装一个字段感觉有点错误,它只需要几行代码,而不仅仅

我有一个抽象基类,我想声明一个字段或一个属性,该字段或属性在继承自父类的每个类中具有不同的值

我想在基类中定义它,这样我就可以在基类方法中引用它-例如,重写ToString以表示“此对象的类型为property/field”。 我有三种方法,我可以看到这样做,但我想知道-什么是最好的或被接受的方式做这件事?新手问题,对不起

选项1:
使用抽象属性并在继承的类上重写它。这得益于强制执行(您必须覆盖它),而且它是干净的。但是,返回一个硬代码值而不是封装一个字段感觉有点错误,它只需要几行代码,而不仅仅是。我还必须为“set”声明一个body,但这不太重要(可能有一种方法可以避免我不知道的事情)

选项2
我可以声明公共字段(或受保护字段)并在继承的类中显式重写它。下面的例子将给我一个使用“new”的警告,我可能可以这样做,但它感觉不对,它打破了多态性,这就是重点。这似乎不是个好主意

abstract class Mother
{
    public int MyInt = 0;
}

class Daughter : Mother
{
    public int MyInt = 1;
}
选项3
我可以使用受保护的字段并在构造函数中设置值。这看起来很整洁,但依赖于我确保构造函数总是设置此值,并且对于多个重载构造函数,总是有可能某些代码路径不会设置值

abstract class Aunt
{
    protected int MyInt;
}

class Niece : Aunt
{
    public Niece()
    {
        MyInt = 1;
    }
}

这是一个有点理论性的问题,我想答案应该是选项1,因为它是唯一安全的选项,但我刚刚开始接触C,我想问一下有更多经验的人。我会选择选项3,但有一个抽象的setMyInt方法,子类被迫实现。这样,您就不会有派生类忘记在构造函数中设置它的问题

abstract class Base 
{
 protected int myInt;
 protected abstract void setMyInt();
}

class Derived : Base 
{
 override protected void setMyInt()
 {
   myInt = 3;
 }
}
顺便说一句,如果您不指定set,请使用选项1;在抽象基类属性中,派生类不必实现它

abstract class Father
{
    abstract public int MyInt { get; }
}

class Son : Father
{
    public override int MyInt
    {
        get { return 1; }
    }
}

如果修改抽象基类以要求构造函数中的属性值,则可以使用选项3,这样就不会错过任何路径。我真的会考虑这个选项。

abstract class Aunt
{
    protected int MyInt;
    protected Aunt(int myInt)
    {
        MyInt = myInt;
    }

}

当然,您仍然可以选择将字段设置为私有,然后根据需要公开受保护或公共属性getter。

您可以定义如下内容:

abstract class Father
{
    //Do you need it public?
    protected readonly int MyInt;
}

class Son : Father
{
    public Son()
    {
        MyInt = 1;
    }
}
通过将该值设置为readonly,可以确保该类的值在对象的生存期内保持不变


我想下一个问题是:为什么需要它?

选项2是非启动选项-您不能覆盖字段,只能隐藏字段

就我个人而言,我每次都会选择选项1。我总是尽量保持田地的私密性。当然,如果你真的需要能够覆盖属性的话。另一个选项是在基类中具有只读属性,该属性由构造函数参数设置:

abstract class Mother
{
    private readonly int myInt;
    public int MyInt { get { return myInt; } }

    protected Mother(int myInt)
    {
        this.myInt = myInt;
    }
}

class Daughter : Mother
{
    public Daughter() : base(1)
    {
    }
}

如果值在实例的生命周期内没有改变,那么这可能是最合适的方法。

选项2是个坏主意。它将导致一种叫做阴影的东西;基本上你有两个不同的“MyInt”成员,一个在母亲,另一个在女儿。问题是,在母亲中实现的方法将引用母亲的“MyInt”,而在女儿中实现的方法将引用女儿的“MyInt”。这可能会导致一些严重的可读性问题,以及以后的混乱


我个人认为最好的选择是3;因为它提供了一个明确的集中值,并且可以由孩子们在内部引用,而无需定义他们自己的字段——这是选项1的问题。

三种解决方案中只有选项1多态的

字段本身不能被重写。这正是选项2返回关键字警告的原因

警告的解决方案不是附加“new”关键字,而是实现选项1

如果需要字段具有多态性,则需要将其包装到属性中。

如果您不需要多态行为,那么选项3是可以的。但是,您应该记住,当在运行时访问属性MyInt时,派生类对返回的值没有控制权。基类本身能够返回此值

这就是属性的真正多态实现的外观,允许派生类进行控制

你可以这样做

class x
{
    private int _myInt;
    public virtual int myInt { get { return _myInt; } set { _myInt = value; } }
}

class y : x
{
    private int _myYInt;
    public override int myInt { get { return _myYInt; } set { _myYInt = value; } }
}
虚拟让你得到一个属性,一个做某事的实体,并且仍然让子类覆盖它。

我这样做了

namespace Core.Text.Menus
{
    public abstract class AbstractBaseClass
    {
        public string SELECT_MODEL;
        public string BROWSE_RECORDS;
        public string SETUP;
    }
}

namespace Core.Text.Menus
{
    public class English : AbstractBaseClass
    {
        public English()
        {
            base.SELECT_MODEL = "Select Model";
            base.BROWSE_RECORDS = "Browse Measurements";
            base.SETUP = "Setup Instrument";
        }
    }
}

这样,您仍然可以使用字段

如果您正在构建一个类,并且希望属性有一个基值,那么在基类中使用
virtual
关键字。这允许您选择性地覆盖该属性

使用上面的示例:

//you may want to also use interfaces.
interface IFather
{
    int MyInt { get; set; }
}


public class Father : IFather
{
    //defaulting the value of this property to 1
    private int myInt = 1;

    public virtual int MyInt
    {
        get { return myInt; }
        set { myInt = value; }
    }
}

public class Son : Father
{
    public override int MyInt
    {
        get {

            //demonstrating that you can access base.properties
            //this will return 1 from the base class
            int baseInt = base.MyInt;

            //add 1 and return new value
            return baseInt + 1;
        }
        set
        {
            //sets the value of the property
            base.MyInt = value;
        }
    }
}
在程序中:

Son son = new Son();
//son.MyInt will equal 2

当您想要有一个带有实现的抽象类时,示例实现。子类必须:

  • 参数化抽象类的实现
  • 完全继承抽象类的实现
  • 有自己的实现
  • 在这种情况下,除了抽象类及其自己的子类之外,实现所需的属性不应可用

        internal abstract class AbstractClass
        {
            //Properties for parameterization from concrete class
            protected abstract string Param1 { get; }
            protected abstract string Param2 { get; }
    
            //Internal fields need for manage state of object
            private string var1;
            private string var2;
    
            internal AbstractClass(string _var1, string _var2)
            {
                this.var1 = _var1;
                this.var2 = _var2;
            }
    
            internal void CalcResult()
            {
                //The result calculation uses Param1, Param2, var1, var2;
            }
        }
    
        internal class ConcreteClassFirst : AbstractClass
        {
            private string param1;
            private string param2;
            protected override string Param1 { get { return param1; } }
            protected override string Param2 { get { return param2; } }
    
            public ConcreteClassFirst(string _var1, string _var2) : base(_var1, _var2) { }
    
            internal void CalcParams()
            {
                //The calculation param1 and param2
            }
        }
    
        internal class ConcreteClassSecond : AbstractClass
        {
            private string param1;
            private string param2;
    
            protected override string Param1 { get { return param1; } }
    
            protected override string Param2 { get { return param2; } }
    
            public ConcreteClassSecond(string _var1, string _var2) : base(_var1, _var2) { }
    
            internal void CalcParams()
            {
                //The calculation param1 and param2
            }
        }
    
        static void Main(string[] args)
        {
            string var1_1 = "val1_1";
            string var1_2 = "val1_2";
    
            ConcreteClassFirst concreteClassFirst = new ConcreteClassFirst(var1_1, var1_2);
            concreteClassFirst.CalcParams();
            concreteClassFirst.CalcResult();
    
            string var2_1 = "val2_1";
            string var2_2 = "val2_2";
    
            ConcreteClassSecond concreteClassSecond = new ConcreteClassSecond(var2_1, var2_2);
            concreteClassSecond.CalcParams();
            concreteClassSecond.CalcResult();
    
            //Param1 and Param2 are not visible in main method
        }
    

    静态是一个糟糕的词汇选择,因为它意味着值在类的所有实例之间共享,当然不是。作为旁白,我真的认为父亲应该应用公式“Y”,母亲在逻辑上应该应用公式“X”。如果我想在父级中提供一个默认实现,而不是抽象的,该怎么办?@AaronFranke制作s
    Son son = new Son();
    //son.MyInt will equal 2
    
        internal abstract class AbstractClass
        {
            //Properties for parameterization from concrete class
            protected abstract string Param1 { get; }
            protected abstract string Param2 { get; }
    
            //Internal fields need for manage state of object
            private string var1;
            private string var2;
    
            internal AbstractClass(string _var1, string _var2)
            {
                this.var1 = _var1;
                this.var2 = _var2;
            }
    
            internal void CalcResult()
            {
                //The result calculation uses Param1, Param2, var1, var2;
            }
        }
    
        internal class ConcreteClassFirst : AbstractClass
        {
            private string param1;
            private string param2;
            protected override string Param1 { get { return param1; } }
            protected override string Param2 { get { return param2; } }
    
            public ConcreteClassFirst(string _var1, string _var2) : base(_var1, _var2) { }
    
            internal void CalcParams()
            {
                //The calculation param1 and param2
            }
        }
    
        internal class ConcreteClassSecond : AbstractClass
        {
            private string param1;
            private string param2;
    
            protected override string Param1 { get { return param1; } }
    
            protected override string Param2 { get { return param2; } }
    
            public ConcreteClassSecond(string _var1, string _var2) : base(_var1, _var2) { }
    
            internal void CalcParams()
            {
                //The calculation param1 and param2
            }
        }
    
        static void Main(string[] args)
        {
            string var1_1 = "val1_1";
            string var1_2 = "val1_2";
    
            ConcreteClassFirst concreteClassFirst = new ConcreteClassFirst(var1_1, var1_2);
            concreteClassFirst.CalcParams();
            concreteClassFirst.CalcResult();
    
            string var2_1 = "val2_1";
            string var2_2 = "val2_2";
    
            ConcreteClassSecond concreteClassSecond = new ConcreteClassSecond(var2_1, var2_2);
            concreteClassSecond.CalcParams();
            concreteClassSecond.CalcResult();
    
            //Param1 and Param2 are not visible in main method
        }