为什么要封装这个字段?

时间:2011-12-01 19:47:57

标签: c# oop coding-style standards encapsulation

我总是被告知从类中封装任何和所有属性......

这是对的:

private string propertyName;
public string PropertyName
{
    get { return propertyName; }
    set { propertyName = value; }
}

这是错误的

Public string PropertyName;

我看不出需要封装的地方...... 对我来说,第一个代码只是无用的冗余代码...... 没有必要封装那个领域......

因此,如果有人能够证明对这个场景的封装是正确的。 (我可以理解其他情况)。

8 个答案:

答案 0 :(得分:7)

在大多数情况下,公共领域在实践中是可以的。毕竟,如果您以后需要从外部将其设置为只读,或者向其setter添加行为,则可以将其更改为属性。因此,您今天可以将其变为公共领域,如果需要,可以在以后进行更改。正确?

问题是,在某些情况下,您无法在以后安全地更改它:

  • 如果使用公共字段编译Foo.dll,并且有人构建引用Foo.dll的Bar.dll,则以后不能将该字段更改为属性的新版本的Foo.dll。您必须让其他人针对您的新Foo.dll重建Bar.dll。对于一些商店来说,这不是一个问题;对于其他人来说,这可能是个大问题。
  • 如果您编写任何反射代码,反映字段与反映属性非常不同。因此,如果您稍后将字段更改为属性,则您的反射代码将会中断。

这两种情况有多重要?可能不是很好。但是先发制人的写作更容易

public string PropertyName { get; set; }
如果你以后必须改变它,那么清理乱七八糟的东西。

并且没有性能成本。无论如何,JIT编译器将内联getter和setter。所以它没有任何成本,并带来一些好处;那时,为什么不使用属性?

答案 1 :(得分:4)

您的主要抱怨是第一次实施的冗长。您的语法对我来说是C#,因此public String PropertyName{get;set;}将是一个不那么详细但等效的语句。有用的是,您可以在不更改用法的情况下更改属性的后备实现。字段与属性的编码风格通常会有所不同,因此至少会导致界面的重构,如果它暴露给其他人,可能会很痛苦。

是的,大部分时间都是矫枉过正。

更新: 根据下面的评论,我将添加一些关于编译器在字段和属性之间注意到的差异。您不能将属性用作ref或out参数,并且如下面由Robert Levy所述,而代码读取相同时,编译器会分配一个函数调用,因此您需要重新编译依赖的程序集。您可以将属性放入接口但不是字段。所以有一些优点和缺点。

答案 2 :(得分:2)

因为您可以稍后更改set以执行验证。 public string PropertyName无法做到这一点,因此您将永远陷入公共属性。


正如其他人在their answers中所说,您可以使用以下语法删除一些错误:

public string PropertyName { get; set; }

答案 3 :(得分:2)

它看起来多余,但这意味着在不破坏使用您的类的其他类的情况下为您提供未来的灵活性。

如果您从public string PropertyName;开始,但稍后切换到定义不动产,则必须重新编译使用您遗嘱的其他类(即使它们的实际代码不必更改)。

在较新版本的C#中,有一个简写:public string MyProperty {get; set; }在幕后创建您不(当前)使用的私有成员。

答案 4 :(得分:1)

您封装以确保数据完整性。例如,如果你有一个类人的年龄属性,你就不希望有人将19348这样的大数字存储到这个变量中。如果使用封装,则可以验证此数字,并在用户尝试执行此类操作时执行错误处理。而“用户”是指使用你的班级的另一个程序员。

答案 5 :(得分:1)

又一个例子。您可以在继承时轻松覆盖属性。

class Base
{
    public virtual string PropertyName { get; set; }
}

class Derived : Base
{
    public override string PropertyName
    {
        get
        {
            return base.PropertyName + " Something";
        }
        set
        {
            base.PropertyName = value;
        }
    }
}

答案 6 :(得分:0)

Encapsulating允许您在不更改类的接口的情况下更改实现细节(意味着没有使用该类的代码需要更改)。例如,您可以稍后添加某种验证或其他逻辑,在内部更改内容作为该属性更改的副作用,甚至替换属性的底层存储),所有这些都无需更改使用此类的任何内容。

总是封装数据是一个好习惯,即使您现在没有看到需要(特别是因为大多数现代IDE会为您自动生成getter和setter)。

答案 7 :(得分:0)

我认为封装访问器方法背后的一般思想是使代码在未来更加灵活(即良好的编程实践)。

如果您需要更改实现细节,在某些属性发生更改时触发通知,跟踪访问属性的次数,它将允许您修改封装方法而不会影响其他代码。

如果您正在编写将来可能会增强的代码,那么额外的工作是值得的,即使以额外的锅炉铭文费用为代价。