类的只读版本,仅用于非固有类

本文关键字:用于 只读 版本 | 更新日期: 2023-09-27 17:52:55

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

这是一个示例代码,正如您所看到的,我使用的是一个"臭布尔解决方案"。我应该如何以更优雅的方式做到这一点?我希望有一些好的模式来解决这个问题。

由于有许多"受保护集"答案而编辑:

如果这样做,我将无法在非固有类中设置类属性,并且在构造函数期间设置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 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";
    }
}

另请参阅限制访问器可访问性(C#编程指南(。

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

甚至更短的

int X { public get; protected set; }

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

您试图做的事情违反了Liskov替换原则,应该避免。

通过继承Foo1,类Foo2承诺遵守超类Foo1公开的接口。即,在Foo1上操作的方法不必关心实际接收的输入是Foo1还是Foo2。这两种类型都公开了相同的接口,因此可以以统一的方式进行操作。

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