class 的只读版本仅适用于非固有 classes

Readonly version of a class only for non inherent classes

我需要 class 的受保护属性版本。这意味着外部 classes 无法更改值,但固有 class 可以。

这是一个示例代码,如您所见,我使用的是"smelly bool solution"。我应该如何以更优雅的方式做到这一点?我希望有一些好的模式解决这个问题。

由于很多 "protected set" 答案而编辑:

这样做我将无法在非固有 classes 中设置 class 属性 并且构造函数期间的 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.
    }
}

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

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)

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

甚至更短

int X { public get; protected set; }

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

您的行为违反了Liskov substitution principle,应该避免。

通过从 Foo1 继承,class Foo2 承诺遵守超级 class Foo1 公开的接口。 IE。在 Foo1 上运行的方法不必关心接收到的输入实际上是 Foo1 还是 Foo2。两种类型都暴露相同的接口,因此可以统一操作。

这就是为什么除了重新考虑您的设计之外,您的问题没有优雅的解决方案。