C# 覆盖子类中的字段或属性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/326223/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Overriding fields or properties in subclasses
提问by Frans
I have an abstract base class and I want to declare a field or a property that will have a different value in each class that inherits from this parent class.
我有一个抽象基类,我想声明一个字段或属性,该字段或属性在从该父类继承的每个类中具有不同的值。
I want to define it in the baseclass so I can reference it in a base class method - for example overriding ToString to say "This object is of type property/field". I have got three ways that I can see of doing this, but I was wondering - what is the best or accepted way of doing this? Newbie question, sorry.
我想在基类中定义它,以便我可以在基类方法中引用它 - 例如覆盖 ToString 说“这个对象是属性/字段类型”。我有三种方法可以看到这样做,但我想知道 - 这样做的最佳或可接受的方法是什么?新手问题,不好意思。
Option 1:
Use an abstract Property and override it on the inherited classes. This benefits from being enforced (you have to override it) and it is clean. But, it feels slightly wrong to return a hard-code value rather than encapsulate a field and it is a few lines of code instead of just. I also have to declare a body for "set" but that is less important (and there is probably a way to avoid that which I am not aware of).
选项 1:
使用抽象属性并在继承的类上覆盖它。这受益于强制执行(您必须覆盖它)并且它很干净。但是,返回一个硬编码值而不是封装一个字段感觉有点错误,它是几行代码而不是仅仅。我还必须为“set”声明一个主体,但这不太重要(并且可能有一种方法可以避免我不知道的情况)。
abstract class Father
{
abstract public int MyInt { get; set;}
}
class Son : Father
{
public override int MyInt
{
get { return 1; }
set { }
}
}
Option 2
I can declare a public field (or a protected field) and explicitly override it in the inherited class. The example below will give me a warning to use "new" and I can probably do that, but it feels wrong and it breaks the polymorphism, which was the whole point. Doesn't seem like a good idea...
选项 2
我可以声明一个公共字段(或受保护的字段)并在继承的类中显式覆盖它。下面的示例将警告我使用“new”,我可能可以这样做,但感觉不对并且它破坏了多态性,这就是重点。似乎不是一个好主意...
abstract class Mother
{
public int MyInt = 0;
}
class Daughter : Mother
{
public int MyInt = 1;
}
Option 3
I can use a protected field and set the value in the constructor. This seems pretty tidy but relies on me ensuring the constructor always sets this and with multiple overloaded constructors there is always a chance some code path won't set the value.
选项 3
我可以使用受保护的字段并在构造函数中设置值。这看起来很整洁,但依赖于我确保构造函数始终设置它,并且对于多个重载的构造函数,总是有可能某些代码路径不会设置该值。
abstract class Aunt
{
protected int MyInt;
}
class Niece : Aunt
{
public Niece()
{
MyInt = 1;
}
}
It's a bit of a theoretical question and I guess the answer has to be option 1 as it is the only safeoption but I am just getting to grips with C# and wanted to ask this of people with more experience.
这是一个有点理论性的问题,我想答案必须是选项 1,因为它是唯一安全的选项,但我刚刚开始使用 C# 并想向有更多经验的人询问这个问题。
采纳答案by Preets
Of the three solutions only Option 1is polymorphic.
在三个解决方案中,只有Option 1是多态的。
Fields by themselves cannot be overridden. Which is exactly why Option 2returns the newkeyword warning.
字段本身不能被覆盖。这正是选项 2返回 新关键字警告的原因。
The solution to the warning is not to append the “new” keyword, but to implement Option 1.
警告的解决方案不是附加“new”关键字,而是实现选项1。
If you need your field to be polymorphic you need to wrap it in a Property.
如果你需要你的字段是多态的,你需要将它包装在一个属性中。
Option 3is OK if you don't need polymorphic behavior. You should remember though, that when at runtime the property MyInt is accessed, the derived class has no control on the value returned. The base class by itself is capable of returning this value.
如果您不需要多态行为,则选项 3是可以的。但是您应该记住,在运行时访问属性 MyInt 时,派生类无法控制返回的值。基类本身能够返回这个值。
This is how a truly polymorphic implementation of your property might look, allowing the derived classes to be in control.
这就是您的属性的真正多态实现的外观,允许派生类处于控制之中。
abstract class Parent
{
abstract public int MyInt { get; }
}
class Father : Parent
{
public override int MyInt
{
get { /* Apply formula "X" and return a value */ }
}
}
class Mother : Parent
{
public override int MyInt
{
get { /* Apply formula "Y" and return a value */ }
}
}
回答by Winston Smith
I'd go with option 3, but have an abstract setMyInt method that subclasses are forced to implement. This way you won't have the problem of a derived class forgetting to set it in the constructor.
我会选择选项 3,但有一个抽象的 setMyInt 方法,子类必须实现该方法。这样你就不会有派生类忘记在构造函数中设置它的问题。
abstract class Base
{
protected int myInt;
protected abstract void setMyInt();
}
class Derived : Base
{
override protected void setMyInt()
{
myInt = 3;
}
}
By the way, with option one, if you don't specify set; in your abstract base class property, the derived class won't have to implement it.
顺便说一句,如果您不指定 set; 在您的抽象基类属性中,派生类不必实现它。
abstract class Father
{
abstract public int MyInt { get; }
}
class Son : Father
{
public override int MyInt
{
get { return 1; }
}
}
回答by Blair Conrad
You can go with option 3 if you modify your abstract base class to require the property value in the constructor, you won't miss any paths. I'd really consider this option.
如果您修改抽象基类以要求构造函数中的属性值,则可以使用选项 3,您将不会错过任何路径。我真的会考虑这个选项。
abstract class Aunt
{
protected int MyInt;
protected Aunt(int myInt)
{
MyInt = myInt;
}
}
Of course, you then still have the option of making the field private and then, depending on the need, exposing a protected or public property getter.
当然,您仍然可以选择将该字段设为私有,然后根据需要公开受保护或公共属性的 getter。
回答by Ant
You could define something like this:
你可以这样定义:
abstract class Father
{
//Do you need it public?
protected readonly int MyInt;
}
class Son : Father
{
public Son()
{
MyInt = 1;
}
}
By setting the value as readonly, it ensures that the value for that class remains unchanged for the lifetime of the object.
通过将该值设置为只读,可以确保该类的值在对象的生命周期内保持不变。
I suppose the next question is: why do you need it?
我想下一个问题是:你为什么需要它?
回答by Jon Skeet
Option 2 is a non-starter - you can't overridefields, you can only hidethem.
选项 2 是一个非启动项 - 您不能覆盖字段,您只能隐藏它们。
Personally, I'd go for option 1 every time. I try to keep fields private at all times. That's if you really need to be able to override the property at all, of course. Another option is to have a read-only property in the base class which is set from a constructor parameter:
就个人而言,我每次都会选择选项 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)
{
}
}
That's probably the most appropriate approach if the value doesn't change over the lifetime of the instance.
如果该值在实例的整个生命周期内没有改变,这可能是最合适的方法。
回答by Jon Skeet
option 2 is a bad idea. It will result in something called shadowing; Basically you have two different "MyInt" members, one in the mother, and the other in the daughter. The problem with this, is that methods that are implemented in the mother will reference the mother's "MyInt" while methods implemented in the daughter will reference the daughter's "MyInt". this can cause some serious readability issues, and confusion later down the line.
选项 2 是个坏主意。它会导致一种叫做阴影的东西;基本上,您有两个不同的“MyInt”成员,一个在母亲中,另一个在女儿中。这样做的问题是,在母亲中实现的方法将引用母亲的“MyInt”,而在女儿中实现的方法将引用女儿的“MyInt”。这可能会导致一些严重的可读性问题,并在以后造成混乱。
Personally, I think the best option is 3; because it provides a clear centralized value, and can be referenced internally by children without the hassle of defining their own fields -- which is the problem with option 1.
我个人认为最好的选择是3;因为它提供了一个明确的集中值,并且可以被孩子们内部引用,而无需定义自己的字段——这是选项 1 的问题。
回答by Joshua G
You could do this
你可以这样做
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; } }
}
virtual lets you get a property a body that does something and still lets sub-classes override it.
virtual 允许您获得一个属性,一个可以执行某些操作的主体,并且仍然让子类覆盖它。
回答by 8r13n
I did this...
我做了这个...
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";
}
}
}
This way you can still use fields.
这样您仍然可以使用字段。
回答by Keith Aymar
If you are building a class and you want there to be a base value for the property, then use the virtual
keyword in the base class. This allows you to optionally override the property.
如果您正在构建一个类并且您希望该属性有一个基值,则virtual
在基类中使用关键字。这允许您选择性地覆盖该属性。
Using your example above:
使用上面的示例:
//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;
}
}
}
In a program:
在一个程序中:
Son son = new Son();
//son.MyInt will equal 2
回答by Belomestnykh Sergey
The example implementation when you want to have an abstract class with implementation. Subclasses must:
当您想要一个带有实现的抽象类时的示例实现。子类必须:
- Parameterize the implementation of an abstract class.
- Fully inherit the implementation of the abstract class;
- Have your own implementation.
- 参数化抽象类的实现。
- 完全继承抽象类的实现;
- 有自己的实现。
In this case, the properties that are necessary for the implementation should not be available for use except for the abstract class and its own subclass.
在这种情况下,除了抽象类和它自己的子类之外,实现所需的属性不应该可用。
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
}