如何禁止使用字段而不是属性?

时间:2014-04-14 06:45:12

标签: c# properties

我的班级中有一个属性,在 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;
}

它会破坏我班级的逻辑!

5 个答案:

答案 0 :(得分:19)

通常,课程应该足够小,这不应该是一个问题。由于该字段为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
}

这不会停止它们,但它可能有助于防止意外使用该字段。

答案 1 :(得分:7)

有一种正确的方法可以做到这一点。考虑一句古老的格言“计算机科学中的所有问题都可以通过另一层次的间接解决”。

您所做的是创建一个知道如何正确设置文本字段值的类。

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);}
    }
}

您可以根据需要随意重命名。

答案 2 :(得分:5)

通过将修改器设置为字段的私有功能,您已经完成了尽可能多的工作。 这个类中,你通常应该知道你对它的字段做了什么,逻辑发生在哪里。

答案 3 :(得分:5)

作为一种替代方法,在discussion with 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字符串。

答案 4 :(得分:1)

您可以使用集合(每种类型一个)作为&#34;支持存储&#34;:

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>集合......但我讨厌它。每种类型一个避免始终投射数据