如何从继承的属性中移除set访问器并保留get和set访问器

3
假设我有一个类层次结构,在创建 B 的实例时,通过构造函数链接设置数字的默认值。由于 _number 的值应为默认值,因此必须重写 Number 属性以删除 set 访问器。
abstract Class A
{
    public int Number
    {
        get
        {
            return _number
        }
        set
        {
            _number = value;
        }
     }
 }

Class B : Class A
{
    public int Number
    {
        get
        {
            return _number
        }
     }
 }

2
我认为这是不可能的,而且有很好的理由:它会违反Liskov替换原则并违反基类合同 - 显然类B 不是A,因为它表现出明显不同的行为。 - Patryk Ćwiek
为什么你不能将setter方法设为“private”? - Adriaan Stander
这违反了SOLID中的Liskov替换原则。请参见http://stackoverflow.com/questions/22838199/override-interface-method-in-another-interface/22838456#22838456 - Murdock
3个回答

2
这是不可能的,也有很好的原因。
实际上,您正在违反Liskov替换原则。Liskov原则指出:
程序中的对象应该可以用它们的子类型的实例替换,而不会改变程序的正确性。
由于您的基类具有公共设置,因此您的派生类也应该如此。
几乎可以将我在覆盖另一个接口中的接口方法中所做的相同论点应用于此处。
由于您可以传递派生类到需要基类的任何地方,那么如果用户在属性上调用该设置会发生什么?
虽然新建该方法似乎是一种可能的解决方案,但实际上是错误的,因为新建隐藏了基本属性并且不会覆盖它。它仍然可访问,因为您没有隐藏设置部分(您只隐藏了getter)。
如果在基类中将setter设置为私有,则setter对于基类和派生类都不会在公共上可见。但是,如果您正在使用构造函数分配,则可以选择此选项。

0
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            B b = new B(10);

            // b.Number = 10; // Error here
        }
    }

    public abstract class A
    {
        public A() { }

        public A(int number)
        {
            Number = number;
        }

        private int _number;

        public virtual int Number
        {
            get
            {
                return _number;
            }
            private set
            {
                _number = value;
            }
        }
    }

    public class B : A
    {
        public B(int number)
            : base(number) { }

        public override int Number
        {
            get
            {
                return base.Number;
            }
        }
    }
}

-1

可能是类似于

class B : A
{
    public new int Number //NEW
    {
        get
        {
            return _number; //NUMBER IS DEFINED IN (A)
        }
     }
 }

但是这个有一个问题。

即使这样可以正常工作

B b = new B(); 
b.Number = 10; //COMPILER ERROR FOR READONLY PROPERTY 

这段代码将会正确编译

A b = new B(); 
b.Number = 10; //NO ERROR

你应该用大号粗体字指出这不是覆盖属性,而是隐藏属性。 - cremor
这是一个危险的答案。因为getter现在引用派生类,setter引用基类。所以如果我认为我正在修改派生类中的_number2,我仍然会在基类中设置_number。 - Murdock
@Murdock:但是你只有一个数字,在基数中。也就是说,如果没有在程序架构中明确指定,就不需要任何重复。 - Tigran

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接