【问题标题】:Can I prevent a private variable from being changed by other objects of the same class?我可以防止私有变量被同一类的其他对象更改吗?
【发布时间】:2019-05-30 15:19:06
【问题描述】:

我正在对实时游戏进行多线程处理,并希望防止一个线程上对象的状态变量从另一个线程设置。这将使防止竞争条件变得更加容易。

不过,我仍然希望能够读取其他对象的状态。我打算使用双缓冲系统,其中一个状态对象用作前缓冲区并进行状态更改,而另一个用作后缓冲区并将(前一帧的)状态提供给其他对象。我需要能够从后备缓冲区读取状态信息以在前缓冲区中进行更改。

问题在于,即使变量设置器是私有的,也可以从同一类的另一个对象更改它。

    public class State
    {
        //Some example state information
        public string StateVar1 { get; private set; }

        //This method will be farmed out to multiple other threads
        public void Update(State aDifferentStateObject)
        {
            StateVar1 = "I want to be able to do this";
            string infoFromAnotherObject = aDifferentStateObject.StateVar1; //I also want to be able to do this
            aDifferentStateObject.StateVar1 = "I don't want to be able to do this, but I can";
        }
    }

【问题讨论】:

  • 您尝试做的事情毫无意义。作为课程的作者,您可以完全控制它的作用。如果您不希望您的类的实例修改其他实例的属性,请不要这样做。
  • 你是对的,我可以控制我在这门课上写的东西。但是我也不是万无一失的,我不能 100% 确定没有人会编辑这个类,而且众所周知,竞态条件很难调试。这是针对未来错误的防御机制。

标签: c# multithreading state access-modifiers


【解决方案1】:

可以从同一类的另一个对象更改它。

你不能阻止你自己的班级设置私人二传手。

我的意思是,毕竟你是那个类的作者,你只需要担心你的手指。

public class SomeOtherNonRelatedClass
{
     public void Update(State aDifferentStateObject)
     {
        // the world is as it should be
        aDifferentStateObject.StateVar1 = "bang!!!" // compiler error
     }
}

如果您想阻止自己更改自己的成员,请使用扩展方法

public class Extensions
{
     public void Update(this State aDifferentStateObject)
     {
        // the world is as it should be
        aDifferentStateObject.StateVar1 = "bang!!!" // compiler error
     }
}

或者让它真正只读(虽然可能没用)

public string StateVar1 { get; }

或支持字段,因此您可以在内部设置它

private string backingField;

public string StateVar1
{
    get => backingField;
}

【讨论】:

  • OP 说“来自同一类的另一个 object”,而不是“来自另一个类”。您自己引用了问题的这一部分,但您似乎误读了它。
  • @IgbyLargeman 然后澄清了规则和可能的解决方案,但是您的评论表示赞赏和采纳
【解决方案2】:

可能不是最直接的解决方案,但保护属性的一种方法是使用接口。

public interface IState
{
    string StateVar1 { get; }
}

public class State:IState
{
    //Some example state information
    public string StateVar1 { get; private set; }

    //This method will be farmed out to multiple other threads
    public void Update(IState aDifferentStateObject)
    {
        StateVar1 = "I want to be able to do this";  // Allowed
        string infoFromAnotherObject = aDifferentStateObject.StateVar1; 
        aDifferentStateObject.StateVar1 = "I don't want to be able to do this, but I can"; // NOT allowed
    }
}

【讨论】:

  • 但是您仍然可以通过简单地引用类实例来修改 StateVar1 属性。 (aDifferentStateObject as State).StateVar1 = "".
  • @IgbyLargeman 是的,可以,只要作为类实例访问,就可以访问。这就是为什么说“不是最直接的解决方案”。这仅在您使用接口时才有效。感谢您提出讨论
【解决方案3】:

如果您正在编写课程,则假定您将使课程按照您希望的方式工作。将内容设为私有的目的是防止您的同事(或客户)在他们处理自己的类/函数/模块时打扰您的班级。
说“我不想做这件事”。有点没抓住重点。

也就是说,一般来说,不太宽松的语言的好处是它们可以防止您的同事编写蹩脚或不惯用的代码。其他答案显示了您可以使用的惯用语,这会使您的同龄人以后更难编辑破坏您漂亮的优雅模式。 Anu Viswan's 投票给我。

【讨论】:

    【解决方案4】:

    添加字段 this0=this 并在设置器中检查 this==this0.

    【讨论】:

    • 如果你创建一个setter,你需要一个backing field。类的所有实例都可以修改所有其他实例的所有字段。
    猜你喜欢
    • 1970-01-01
    • 2012-12-01
    • 1970-01-01
    • 2018-09-01
    • 2011-07-10
    • 2020-03-12
    • 2016-07-15
    • 2017-12-20
    • 2017-10-31
    相关资源
    最近更新 更多