【问题标题】:Why prefer Properties to public variables? [duplicate]为什么更喜欢属性而不是公共变量? [复制]
【发布时间】:2010-10-18 17:56:27
【问题描述】:

其他能够在 setter 中检查值是否有更根本的理由更喜欢属性而不是公共变量?

【问题讨论】:

标签: c# syntax


【解决方案1】:

我们以前有过这个主题,但我现在找不到任何东西。

简而言之:您的需求可能会发生变化:现在没有健全性检查,将来可能需要。但是,如果您将公共字段更改为属性,则会破坏二进制兼容性:每个使用您的代码/库的客户端都必须重新编译。

不好,因为它可能会花费很多钱。

从一开始就使用属性可以避免这个问题。这甚至适用于不属于库的代码。为什么?因为你永远不知道:代码(即使是高度特定于领域的!)可能证明是有用的,所以你想将它重构为一个库。如果您已经在使用属性来代替公共/受保护字段,那么这个重构过程显然会变得容易得多。

此外,在 C# 3.0 中编写公共属性很容易,因为您可以使用自动实现的属性,从而节省大量代码:

public DataType MyProperty { get; set; }

将为您实现必要的支持字段和 getter/setter 代码。

我将添加一个个人说明:.NET 在这方面的行为有些懒惰。编译器可以动态地将公共字段更改为属性,从而避免了这个问题。 VB6 已经为 COM 公开的类做到了这一点,我认为 VB.NET 和 C# 完全没有理由不这样做。也许编译器团队中的某个人(Jared?)可以对此发表评论。

【讨论】:

  • 忽略应该问题,编译器无法执行此操作的原因有很多。有两个原因立即浮现在脑海。 1) 名称和 2) 调用属性与访问字段(性能、引用和输出)不同。不幸的是,这里没有足够的空间来真正发表评论
  • (cont) 并且线程已关闭。但简短的版本是用户要求一个项目,而你给他们一个不相等的替代品。当您这样做时,用户通常会不高兴。
  • 感谢您的回答,杰瑞德。 :-)
  • 我也有同样的想法,但和往常一样,结构会导致问题:v.S.M = 5 将 5 分配给结构 S 的成员 M。如果 S 是字段,则没有问题。如果它是一个属性,这只会修改从属性获取器返回的 S 的临时副本中的 M。可变结构是万恶之源!
  • “如果您将公共字段更改为属性,这会破坏二进制兼容性:每个使用您的代码/库的客户端都必须重新编译”...这经常被引用,但似乎是错误的我。你有没有想过第三方向你发送了某个程序集的 vNew 的情况,并且由于方法/类/命名空间的更改,你无论如何都不必重新编译?通常你会想要重新编译以使用 vNew 中的一些东西。
【解决方案2】:

简而言之:

  • 您可以控制访问(只读,
    只写,读/写)
  • 您可以在设置时验证值 一个属性(检查 null 等)
  • 你可以做额外的处理, 比如延迟初始化
  • 您可以更改底层证券 执行。例如,一个 财产可能由成员支持 现在变量,但你可以改变它 由数据库行支持,而无需 破坏任何用户代码。

【讨论】:

  • C# readonly 关键字呢?
【解决方案3】:

Jeff Atwood has blogged about it:

如上图所示,创建一个微不足道的属性是有正当理由的:

  • 反射对变量和属性的工作方式不同,因此如果您依赖反射,则可以更轻松地使用所有属性。
  • 您不能对变量进行数据绑定。
  • 将变量更改为属性是a breaking change

很遗憾,变量和属性之间存在如此多无意义的摩擦;大多数时候他们做同样的事情。 Kevin Dente 提出了一些新语法,可以让我们两全其美:

public property int Name;

但是,如果变量和属性之间的区别是一个持续存在的问题,我想知道是否需要更激进的解决方案。 难道我们不能完全抛弃变量,转而使用属性吗? 属性难道不能做与变量完全相同的事情,但可以更好地控制可见性吗?

【讨论】:

  • 那个博客链接不能正常工作了。
【解决方案4】:

将来将字段更改为属性被视为重大更改。字段被认为是类的实现细节,公开它们会破坏封装。

【讨论】:

  • 如果调用代码不能被重新编译,这只是一个破坏性的变化,大多数时候你拥有调用者代码并且它是由同一个构建系统编译的。因此,对于 .NET 框架团队之外的大多数人来说,这不是问题。
  • @Ian Ringrose:它也不完全兼容源代码。例如,您的代码可能会执行 ref obj.MyField。在不更改源的情况下,您无法将 MyField 更改为 MyProperty
  • @Ian:这是一个突破性的变化 - msdn.microsoft.com/en-us/library/ms182141(VS.80).aspx
【解决方案5】:

您还可以使用属性保护写访问并允许读访问:

public int Version { get; private set; }

【讨论】:

  • 这实际上不能编译。我想你的意思是:public int Version { get; private set; }
【解决方案6】:

如果你在一个封闭的环境中工作——你不开发 SDK,所有的类都在同一个项目框架中使用——没有区别。

通常的论点是“将来您可能需要对值进行一些检查,因此使用属性更容易”。我根本不买。

使用公共字段更具可读性,更少装饰,更易于使用。

【讨论】:

    【解决方案7】:

    使用属性使您的代码更加面向对象。通过公开成员变量,您可以公开您的实现。

    另请参阅 C# 编程指南中的 link

    【讨论】:

      【解决方案8】:

      是的。

      考虑一个现在包含一个字符串的公共变量,您可以简单地设置它。但是,如果您决定该公共变量应该包含一个应该用字符串初始化的对象,那么您将不得不使用原始对象更改所有代码。但是,如果您使用 setter,则只需更改 setter 即可使用提供的字符串初始化对象。

      【讨论】:

        猜你喜欢
        • 2012-12-25
        • 1970-01-01
        • 2015-08-13
        • 1970-01-01
        • 1970-01-01
        • 2011-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多