只有非固有类的只读类版本

时间:2015-06-03 14:10:29

标签: c# inheritance properties

我需要一个类的受保护属性版本。意味着外部类不能改变值,但固有类可以。

以下是一个示例代码,您可以看到,我正在使用" smelly bool解决方案"。我该怎样以更优雅的方式做到这一点?我希望这个问题有一些很好的模式解决方案。

编辑由于很多"受保护的设置"答案:

这样做我将无法在非固有类中设置类属性,并且构造函数中的IsReadOnly属性和值将无用。

public class Foo1
{
    protected bool smellyBoolSolution = false;

    public bool IsReadOnly { get; private set; }

    private int x;

    public int X
    {
        get { return x; }
        set
        {
            CheckCanWrite();
            x = value;
        }
    }

    public Foo1(bool isReadOnly)
    {
        IsReadOnly = isReadOnly;
    }

    private void CheckCanWrite()
    {
        if (IsReadOnly && !smellyBoolSolution)
            throw new InvalidOperationException("Class is read only.");
    }
}

public class Foo2 : Foo1
{
    public Foo2()
        : base(true)
    {
    }

    public void DoStuff()
    {
        int newX = 1;
        //.... calculates new x

        //Oh, using the smelly bool solution I can change my base class properties
        base.smellyBoolSolution = true;
        base.X = newX;
        base.smellyBoolSolution = false;
    }
}

//Usage
public class Foo3
{
    public void DoStuff()
    {
        //Foo1 in writable version
        Foo1 f = new Foo1(false);
        f.X = 1;

        //Foo2 inherents Foo1 and only Foo2 can change X
        Foo2 f2 = new Foo2();
        f2.X = 1; //Exception here.
    }
}

3 个答案:

答案 0 :(得分:1)

使用受保护的字段来启用从基类和继承类的写入,公开一个公共只读属性:

public class A
{
    protected string FooField;
    public string Foo { get { return FooField; } }

    public A()
    {
        FooField = "A";
    }
}

public class B : A
{
    public B()
        : base()
    {
        FooField = "B";
    }
}

您甚至可以使用自动属性执行此操作:

public class A
{
    public string Foo { get; protected set; }

    public A()
    {
        Foo = "A";
    }
}

public class B : A
{
    public B()
        : base()
    {
        Foo = "B";
    }
}

另见Restricting Accessor Accessibility (C# Programming Guide)

答案 1 :(得分:0)

private int x
int X
{
    public get { return x; }
    protected set { x = value; }
}

甚至更短

int X { public get; protected set; }

这两个解决方案并不完全相同,因为第一个解决方案使用显式实现的属性,第二个解决方案自动实现属性。

答案 2 :(得分:0)

您要做的是违反Liskov substitution principle,应该避免。

继承自<h4 data-bind="html:Product() + '<small>' + Price() + '</small>'"></h4> ,类Foo1承诺遵守超类Foo2公开的接口。即在Foo1上运行的方法不必关心所接收的输入是实际上是Foo1还是Foo1。两种类型都暴露相同的接口,因此可以统一的方式进行操作。

这就是为什么除了重新思考你的设计之外没有优雅的解决方案。