【问题标题】:Should I use a private field of a public property inside a class where I declare that property?我应该在声明该属性的类中使用公共属性的私有字段吗?
【发布时间】:2014-01-10 11:25:30
【问题描述】:

假设我有这样的课程:

public class A
{
    private BaseSettings fieldA;
    public ISettings PropertyA
    {
         get {return fieldA;}
         set {fieldA= value as BaseSettings;}
    }
}

BaseSettings 实现 ISettings 的地方。在 A 类中,如果我想访问 BaseSettings 的名为 PropertyB 的属性,这是一个好习惯:

fieldA.PropertyB;

((BaseSettings)PropertyA).PropertyB;

有人可能会说第一种方法可能会隐藏属性更改时间的提示。例如,代码可能会侦听 PropertyChangedEvent,然后更改属性的值而不引发事件。

另一个人可能会说第二种方法可能会暴露一个风险,即当不熟悉当前代码的人修改它时,他可能会将 PropertyA 转换为实现 ISettings 的不同类型。

这两种方法都有其缺点。在良好的编程实践中,哪个更可取?

编辑: 基于以下cmets添加:

我同意将支持字段设置为 ISettings 绝对有意义。但是我应该怎么做才能确保 PropertyA 始终是 BaseSettings 的类型。这会引发一个问题:“那你为什么不将属性和支持字段都设置为 BaseSettings?”。

属性和它的支持字段不同的原因是A类也实现了这样的接口

public interface IControlWithSettings
{
     ISettings OwnerSettings
     {
         get;
         set;
     }
     ISettings Settings
     {
         get;
         set;
     }
}

所以实际的 classA 应该是这样的

public class BaseForm: Form, IControlWithSettings
{
    private BaseFormSettings settings;
    public ISettings Settings
    {
         get {return settings;}
         set {settings= value as BaseFormSettings;}
    }
}

我还有另一个类 B 也会实现 IControlWithSettings

public class BaseUserControl: UserControl, IControlWithSettings
{
    private BaseUserControlSettings settings;
    public ISettings Settings
    {
         get {return settings;}
         set {settings= value as BaseUserControlSettings ;}
    }
}

BaseFormSettings : ISettingsBaseUserControlSettings : ISettings 。这是实际的ISettings界面

public interface ISettings
{
    Dictionary<string, ISettings> Children { get; set; }
}

'as' 转换是我放入 setter 的副作用,因此如果设置设置为错误,它将忽略并返回 null。我在某处读到说我不应该在 setter 中抛出异常。因此,将其设为 null 是我通知有错误发生的方式。

那么更好的方法是什么。是不是我设计错了?

【问题讨论】:

  • 为什么要使用特定类型来支持属性,而使用泛型类型来公开属性?这对您班级的消费者来说充其量是个问题。
  • 同意@JustinNiessner。您可以采用另一种方式(私有字段的接口,公共属性的特定类型),但这样做会导致问题。
  • 您最好将 ISettings 用于支持字段和属性声明。如果 A 类需要使用 PropertyB,那么它应该由接口公开
  • 另见我关于这个主题的文章。 blogs.msdn.com/b/ericlippert/archive/2009/01/14/…

标签: c#


【解决方案1】:

正如您所说,这两种方法都有其缺点,并且还取决于属性设置器是否可能包含一些额外的逻辑(例如验证),您可以在类内部使用或规避这些额外的逻辑。
如果没有任何反对意见,我将使用直接访问该字段的方式。它更整洁,并且避免了所有这些类型转换的东西。

但一般来说:为什么要使用派生类型支持您的属性,而属性本身具有接口类型?这没有多大意义。为什么不只是:

public class A
{
    public ISettings PropertyA { get; set; }
}

这样会干净得多,甚至不会出现您的问题。

编辑(基于答案的编辑)
在支持字段的“双重使用”的情况下,类型转换是有意义的。但我不认为(以前从未听说过)从属性设置器中抛出异常是一件坏事。相反:验证值并在未通过时抛出异常是一种非常常见的模式。
因此,在您的具体情况下,我将验证正确类型的值,如果不正确则抛出,并在内部使用支持字段绕过此类型检查。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-19
    • 1970-01-01
    • 1970-01-01
    • 2011-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多