假设我有一个这样的课程:
public class A
{
private BaseSettings fieldA;
public ISettings PropertyA
{
get {return fieldA;}
set {fieldA= value as BaseSettings;}
}
}
BaseSettings实现ISettings。在A类中,如果我想访问名为PropertyB的BaseSettings属性,这是一个很好的做法:
fieldA.PropertyB;
或
((BaseSettings)PropertyA).PropertyB;
可以说第一种方法可能会隐藏属性更改时的提示。例如,代码可以侦听PropertyChangedEvent,然后在不引发事件的情况下更改属性值。
另一个人可能会说第二种方法可能会暴露出一种风险,即当一个不熟悉当前代码的人修改它时,他可能会将PropertyA转换为实现ISettings的不同类型。
这两种方法都有其缺点。在一个好的编程实践中,哪一个应该更优选?
修改 根据以下评论添加:
我同意将支持字段设置为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 : ISettings
和BaseUserControlSettings : ISettings
。这是实际的ISettings界面
public interface ISettings
{
Dictionary<string, ISettings> Children { get; set; }
}
'as'强制转换是我放入setter的副作用,因此如果将设置设置为错误,它将忽略并返回null。我在某处读到说我不应该在setter中抛出异常。因此,将其设为null是告知已经出现问题的方法。
那么更好的方法是什么呢?我设计错了吗?
答案 0 :(得分:1)
正如你所说,这两种方法都有它们的缺点,它还取决于属性设置器是否包含一些额外的逻辑(例如验证),并且你可以在类中使用或绕过这个额外的逻辑。
如果没有任何反对意见,我将使用直接访问该字段。它更整洁,它避免了所有这些类型转换的东西。
但一般情况下:为什么你会用派生类型支持你的属性,而属性本身有接口类型?这没有多大意义。为什么不呢:
public class A
{
public ISettings PropertyA { get; set; }
}
这会更清洁,你的问题甚至不会出现。
编辑(根据答案的编辑)
在支持字段“双重使用”的情况下,类型转换是有意义的。但我不认为(之前从未听说过)从属性设置器中抛出异常是件坏事。相反:验证值并在未通过时抛出异常是一种非常常见的模式
因此,在您的具体情况下,我将验证正确类型的值,如果它不正确则抛出,并在内部使用支持字段来绕过此类型检查。