所以我有以下代码片段:
private Nullable<decimal> _excessWages;
public decimal ExcessWages
{
get
{
return _excessWages ?? CalculateExcessWages();
}
set
{
if (value != CalculateExcessWages())
_excessWages = value;
else
_excessWages = null;
}
}
所以基本上我试图实现的行为是,如果一个字段留空或被赋值等于计算出的值,则使用计算值,否则存储指定的值。
我有很多字段需要支持这样的覆盖。这是实现这一目标的最佳方式吗?如果不是你会建议什么?
答案 0 :(得分:2)
我主要根据Vlad的建议对此进行了研究。事实证明,你可以使用一个通用类来抽象它。结果如下:
public class Overridable<T>
{
private Func<T> _calculate;
private readonly Func<T, T, bool> _compare;
protected T _t;
public Overridable(Func<T> calculate, Func<T, T, bool> compare)
{
_calculate = calculate;
_compare = compare;
}
public T Value
{
get { return _compare(_t, default(T)) ? _calculate() : _t; }
set { _t = _compare(value, _calculate()) ? default(T) : value; }
}
}
您需要传入一个比较委托,因为在您将其设置为子类之前,该类型是未知的。所以一个简单的==
不会削减它。我使用了一个简单的路由并使用了一个Func委托,但是如果由于某种原因它必须适应.NET 2.0,那么可以用普通委托替换它。
您会注意到我使用的是default(T)
而不是null
。这是有效的,因为Nullable<T>
的默认值是null
(或者更确切地说,未定义,但它的结果相同)。
这并不妨碍您尝试为非可空类型声明Overridable<T>
。你最终得到的不是通过运行时错误,但它没有那么有用。尝试将Overridable<decimal>.Value
设置为null
会导致编译错误。将其设置为default(decimal)
会使其恢复为计算值。
我选择了这条路由,因为我正在使用它的类中的属性需要填充一个最终作为xml传输的可序列化对象。 xml的模式包括定义为整数,小数和字符串混合的数字字段。
然后使用Overriddable类,如下所示:
private Overridable<decimal?> _excessWages =
new Overridable<decimal?>(CalculateExcessWages, (x,y) => x == y);
public virtual decimal? ExcessWages
{
get
{
return _excessWages.Value;
}
set
{
_excessWages.Value = value;
}
}
我遇到的唯一问题是CalculateExcessWages
是非静态方法,因此无法在字段初始值设定项中使用。由于我的类中的所有属性都是非静态的,因此我必须初始化构造函数中的所有支持字段。
答案 1 :(得分:1)
您可以为此创建一个类包装器。
class OverridableValue<T>
{
public OverridableValue<T>(Func<T> calculator)
{
_calculator = calculator;
}
private Nullable<T> _t;
private Func<T> _calculator;
public T Get()
{
return return _t ?? _calculator();
}
public void Set(T value)
{
_t = (value != _calculator()) ? value : null;
}
}
它在语法上并不那么甜美,但至少可以省去一些按键。
现在您可以像这样使用它:
class Foo
{
OverridableValue<decimal> _excessWages =
new OverridableValue<decimal>(CalculateExcessWages);
public decimal ExcessWages
{
get { return _excessWages.Get(); }
set { _excessWages.Set(value); }
}
...
}
优点是整个逻辑隐藏在课堂上。
答案 2 :(得分:1)
你可以通过定义一个方便的set / get helper方法
来做到这一点private static T GetUtil<T>(ref Nullable<T> value, Func<T> calc) {
return value ?? calc();
}
private static void SetUtil<T>(ref Nullable<T> value, T newValue, Func<T> calc) {
if ( newValue != calc() ) {
value = newValue
} else {
value = null;
}
}
private Nullable<decimal> _excessWages;
public decimal ExcessWages
{
get { return GetUtil(ref _excessWages, CalculateExcessWages); }
set { SetUtil(ref _excessWages, value CalculateExcessWages); }
}
答案 3 :(得分:0)
这看起来很合理。我可能做的唯一改变是缓存CalculateExcessWages()
,如果它很昂贵,可以缓存:
private Nullable<decimal> _excessWages;
private Nullable<decimal> _excessWagesCalculated;
public virtual decimal ExcessWages
{
get
{
if (_excessWagesCalculated == null)
_excessWagesCalculated = CalculateExcessWages();
return _excessWages ?? _excessWagesCalculated;
}
set
{
if (_excessWagesCalculated == null)
_excessWagesCalculated = CalculateExcessWages();
if (value != _excessWagesCalculated)
_excessWages = value;
else
_excessWages = null;
}
}
但是,这比你的代码更多,我认为你正在寻求简化。