C# 锁定对象以防止任何数据更改
这有点奇怪 假设我有以下课程:C# 锁定对象以防止任何数据更改,c#,C#,这有点奇怪 假设我有以下课程: public class Wibble { public string Foo {get;set;} public string Bar {get;set;} } 此类用于更新/更改Foo和Bar值的过程。但是,在流程中的某一点之后,我希望“锁定”实例,以防止进行任何更改。所以问题是如何最好地做到这一点 某种解决方案是这样的: public class Wibble { private string _foo; private string _b
public class Wibble
{
public string Foo {get;set;}
public string Bar {get;set;}
}
此类用于更新/更改Foo和Bar值的过程。但是,在流程中的某一点之后,我希望“锁定”实例,以防止进行任何更改。所以问题是如何最好地做到这一点
某种解决方案是这样的:
public class Wibble
{
private string _foo;
private string _bar;
public bool Locked {get; set;}
public string Foo
{
get
{
return this._foo
}
set
{
if (this.Locked)
{
throw new ObjectIsLockedException()
}
this._foo = value;
}
}
public string Bar
{
get
{
return this._bar
}
set
{
if (this.Locked)
{
throw new ObjectIsLockedException()
}
this._bar = value;
}
}
}
然而,这似乎有点不雅
之所以想这样做,是因为我有一个应用程序框架,它使用外部开发的插件来使用这个类。Wibble类被传递到插件中,但是其中一些插件永远不应该更改内容,有些插件可以。这背后的意图是捕捉开发集成问题,而不是运行时生产问题。将对象“锁定”可以快速识别未按指定编码的插件。不能使对象不可变 您可以点击以下帖子: 但我认为你总是可以通过反射来改变属性值 更新 “…实际上,字符串对象并不是这样 不可变,据我所知,至少有两种方法可以断开字符串 不变性。使用如本代码示例所示的指针和一些高级系统。反射用法……”
我建议: 不可变的基类:
public class Wibble
{
public string Foo { get; private set; }
public string Bar { get; private set; }
public Wibble(string foo, string bar)
{
this.Foo = foo;
this.Bar = bar
}
}
然后是一个可以更改的可变类,然后在时机成熟时创建一个不可变的副本
public class MutableWibble
{
public string Foo { get; set; }
public string Bar { get; set; }
public Wibble CreateImmutableWibble()
{
return new Wibble(this.Foo, this.Bar);
}
}
我记不清C#的确切语法,但你明白了
进一步阅读:我实现了一些类似于锁定模式的东西,但也使用了一个只读接口,该接口由包含实际类数据的私有子类实现,这样您就可以传递数据的明显只读视图,并且不能向上转换为原始的“可变版本”。锁定纯粹是为了防止数据提供程序在提供了不可变视图后进行进一步的更改
它工作得相当好,但有点尴尬,正如你所注意到的。我认为,拥有可变的“构建器”对象,然后生成不可变的快照,实际上更干净。想想StringBuilder和String。这意味着您复制了一些属性代码,并且必须编写例程来进行复制,但在我看来,这比在每个属性上都有一个写锁要轻松得多。编译时很明显,快照应该是只读的,构建器的用户不能修改它之前创建的快照。另一个选项是使用BinaryFormatter创建要“锁定”的对象的成员克隆。虽然您没有锁定对象,但您正在创建一个快照,可以在原始快照保持不变的情况下将其丢弃。这让我想起Eric Lippert所谓的“冰棒不变性”。请参阅:我问了一个类似的问题,Lippert先生很好地描述了一些需要注意的陷阱。我还发布了一个我最终使用的示例。实际上,我不建议将Wibble作为基类,因为这只是引入了将可变Wibble作为Wibble传递的可能性,这意味着给定的Wibble实例可能是可变的,也可能不是可变的。@Dan:我修正了@Joe的答案,并删除了基类,因为这永远不会按照他想要的方式工作。如果没有基类(以及对代码的一些更改),它现在可以工作了。@Steven-是的,那太愚蠢了,谢谢你的修复。我添加了
readonly
s作为事后考虑。但我支持拥有一个不可变的基类。Scala使用HashMap实现了这一点,Objective-C使用NSMutableArray实现了这一点(尽管实现非常混乱)。我不想卷入编辑大战,但我会坚持拥有一个不可变的基类。仅供参考:和@Dan我不同意。如果您对MutableWibble
指针有Wibble
引用,则具有Wibble
引用的代码无论如何都不会期望能够对对象进行变异。在.NET中,在完全信任的情况下运行时,您可以做任何您想做的事情。您可以使用指针在您想要的任何位置进行写入。完全信任运行意味着您关闭了.NET的安全机制,它仍然需要反射或指针来写入不可变结构。这不是我们所说的“一成不变”的意思,因为那是欺骗和射中你自己的脚。因此,尽管我们实际上可以改变一切,但是我们考虑诸如<代码>字符串< /代码>不可变的东西。即使是Pattrick Smacchia的文章,你也提到了调用String
immutable。是的,你是对的。。。但在我看来,如果有选择做一件事,你可以建议你可以做。我想知道通过反射你总是可以改变一个类是很有趣的。你总是可以通过内存操作改变地址空间中的任何东西。在某种程度上,您可以根据预期的使用模式对语言进行陈述。在某种程度上,如果有人想惹麻烦,关于c#java或其他任何东西的每一句话都可能被认为是错误的。