如何禁止使用字段而不是属性
本文关键字:字段 属性 何禁止 禁止 | 更新日期: 2023-09-27 17:58:15
我的类中有一个属性,它在set访问器中有很多逻辑:
private String text;
public String Text
{
get { return text; }
private set
{
// some actions with a value
value = value.Replace('a', 'b');
text = value;
}
}
如何防止其他开发人员(甚至我)更改类内部的字段而不是属性?
如果有人写这样的东西:
public Test(String text)
{
this.text = text;
}
这将打破我班的逻辑!
通常,类应该足够小,这不应该是一个问题。由于字段是private
,因此只有同一类型内的代码才能访问该字段。然而,如果你需要强调重要性,你可以这样做:
[Obsolete("Use the Text property, or I break your legs; fair warning")]
private string text;
public string Text
{
#pragma warning disable 0618
get { return text; }
private set
{
// some actions with a value
value = value.Replace('a', 'b');
text = value;
}
#pragma warning restore 0618
}
这并不能阻止它们,但可能有助于防止意外使用该字段。
有一种正确的方法可以做到这一点。考虑一下古老的格言"计算机科学中的所有问题都可以通过另一种间接方法来解决"。
您所做的是创建一个知道如何正确设置文本字段值的类。
class TextSetter
{
private string text;
public TextSetter(string text)
{
Text = text;
}
public string Text
{
get{ return text;}
set{ text = value.Replace('a', 'b');}
}
}
然后在你的第一节课上,而不是private string text;
您有private TextSetter text
;现在,任何人都不可能意外地直接设置值。
如果这是的一个常见问题,你甚至可以对此进行概括
class FieldSetter<T>
{
private T field;
private Func<T, T> setter;
public FieldSetter(Func<T, T> setter, T field)
{
this.setter = setter
Value = field;
}
public T Value
{
get{ return field;}
set{ field = setter(value);}
}
}
您可以随意重命名。
作为一种替代方法,在与Binary Worrier(注释)讨论的基础上,您可以执行以下操作:
internal struct SanitizedText {
private readonly string value;
private SanitizedText(string value) {
this.value = value;
}
public static implicit operator string (SanitizedText value) {
return value.value;
}
public static implicit operator SanitizedText(string value) {
if (value != null) value = value.Replace('a', 'b');
return new SanitizedText(value);
}
}
然后简单地说:
private SanitizedText text;
public string Text {
get { return text; }
set { text = value; }
}
这做了所有相同的验证,但不可能滥用:您不能创建绕过验证的SanitizedText
值;同样,它不需要更多的空间(struct
的大小就是内容的大小:1个引用),并且不需要分配。它甚至以同样的方式默认为null
字符串。
您已经通过将字段的修饰符设置为private所做的一切都是您所能做的。在类中,您通常应该知道如何处理它的字段,逻辑发生在哪里。
您可以使用集合(每种类型一个)作为"后备存储":
private static readonly Dictionary<string, int> __intFields = new Dictionary<string, int>();
private static readonly Dictionary<string, string> __stringFields = new Dictionary<string, string>();
public static string StringProp
{
get
{
var fieldValue = default(string);
__stringFields .TryGetValue("StringProp", out fieldValue);
return fieldValue;
}
set
{
var manipulatedValue = applyOtherCode(value); // the rest of the code
__stringFields ["StringProp"] = manipulatedValue
}
}
public static int IntProp
{
get
{
var fieldValue = default(int);
__intFields .TryGetValue("IntProp", out fieldValue);
return fieldValue;
}
set
{
var manipulatedValue = applyOtherCode(value); // the rest of the code
__intFields ["IntProp"] = manipulatedValue
}
}
// There is no field for anyone to mistakenly access!
丑陋、冗长、不可重构。。。但它完成了任务。如果性能是您最后关心的问题(如果是之一),您可以通过Reflection获取属性名称,并避免使用魔术串。
我最初只有一个<string, object>
集合。。。但我讨厌它。每种类型一个避免了一直投射数据