【问题标题】:Object read only when accessed through/as another object's field对象在通过/作为另一个对象的字段访问时只读
【发布时间】:2012-06-20 07:07:58
【问题描述】:

情况:

我经常遇到这个问题,但不知道如何解决。虽然我不知道在哪里以及如何寻找答案。 所以就在这里。当您将一些对象存储到其他对象中时,您可以将它们设置为只读,或者仅使用 getter,这是相同的。这样你就不能改变 MyInt 的值了

public class ClassA {

    public readonly int MyInt;

    public string MyString;

}

如果我想按如下方式将它放入容器中也没问题:

public class ClassB {

    public readonly ClassA MyClassA;

    public string MyString;

}

这仍将按预期工作。 MyInt 是只读的,而 MyStringA 不是。

问题:

但我仍然可以获取 MyClassA 并设置 MyClassA.MyStringA。 有没有办法拥有一个“更严格”的只读系统? 对于上面的示例,如果 MyClassA 是,我希望 MyClassA 的字段都是只读的。

我能想到的唯一解决方案是拥有另一个 MyClassAreadonly 类。但这看起来很丑陋,也不方便。

上下文:

我寻找这种行为的原因是我希望 MyClassB.MyString 在设置 MyClassB.MyClassA.MyString 之前添加逻辑(如触发事件)。因此,另一种解决方案是通过将 ClassB.MyClassA 设置为私有来简单地不显示它。但是能够检索 MyClassA 真是太好了!但是如果我检索它并修改它,我会错过 ClassB 逻辑!

PS:尽管我想不通,但我希望已经足够清楚了。

【问题讨论】:

  • 查看 Eric Lippert 的旧 blog post,他在其中讨论了“深度”不变性(C# 中目前不存在)

标签: c# object properties readonly


【解决方案1】:

您可以像这样将ClassA 的属性包装到ClassB 的属性中:

public class ClassB
{
    private readonly ClassA _myClassA = new ClassA();
    private string _myString;

    public string MyString 
    { 
        get
        {
            // your logic here
            return _myString;
        } 
        set 
        {
            // your logic here
            _myString = value;
        }
    }
    public string MyStringA { get { return _myClassA.MyString;}}
    public int MyIntA { get { return _myClassA.MyInt; }}
}

【讨论】:

  • 是的,这就是我在“上下文”中想到的解决方案。但是你不能直接检索_myClassA。
【解决方案2】:

如何向 ClassA 添加一个事件,然后 ClassB 可以处理以实现附加逻辑?

public class ClassA
{
    public readonly int MyInt;

    private string _myString;

    public string MyString
    {
        get
        {
            return _myString;
        }
        set
        {
            _myString = value;
            if (MyStringChanged != null)
            {
                MyStringChanged(this, new EventArgs());
            }
        }
    }

    public event EventHandler MyStringChanged;
}


public class ClassB
{
    public readonly ClassA MyClassA;

    //It sounds like you wanted to use ClassB.MyString to manipulate ClassA.MyString, so you probably won't need this anymore?
    //public string MyString;

    public ClassB()
    {
        MyClassA = new ClassA();
        MyClassA.MyStringChanged += new EventHandler(MyClassA_MyStringChanged);
    }

    private void MyClassA_MyStringChanged(object sender, EventArgs e)
    {
        //Add your logic here
    }
}

【讨论】:

  • 是的,这是另一种解决方案。但这对于它的服务目的来说有点太高了。
【解决方案3】:

“深度”不变性

正如@Damien_The_Unbeliever 在评论中所述,here 是我问题的完美“答案”。我把答案放在引号之间,因为目前 C# 中没有内置的解决方案。

解决我的问题的最接近的替代方法是为我想以这种方式使用的对象 (MyClassA) 设置一个不可变外观

谢谢达米安。

关于该主题的另一篇文章:http://www.bluebytesoftware.com/blog/2007/11/11/ImmutableTypesForC.aspx

【讨论】:

    猜你喜欢
    • 2022-01-15
    • 1970-01-01
    • 2012-05-19
    • 1970-01-01
    • 1970-01-01
    • 2021-01-11
    • 2013-05-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多