我知道标题很困惑。以下是我的场景
我的服务有一个契约(Contract)对象,如下所示。
class UpdateRequest
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; }
public decimal Salary { get; set; }
}
现在,上述类的合约对象被传递给更新数据库中记录的方法。假设我想更新一个 ID 为 33 的员工,但我只想更改其名称,而我想单独保留薪水。
一种方法是不用担心这些细节并更新所有内容,但这需要我的服务的客户也将薪水值传递给我,这样它就不会被覆盖为默认(十进制)值。
我能想到的另一种方法是创建以下类型
public class TrackedValue<TInternal> : where TInternal:new
{
private TInternal value = default(TInternal);
public TInternal Value { get; }
private bool initialized;
public static implicit operator TrackedValue<TInternal>(TInternal v)
{
return new TrackedValue<TInternal> { value = v, initialized = true };
}
}
还有别的办法吗? .NET 没有像上面那样的东西吗?我假设如果他们有像 Nullable 这样的东西,他们也必须有解决这个问题的东西。
可空类型对我没有帮助。在某些用例中,我必须将某些表列的现有值更改为 null。那会把它扔掉。
更新:有些人可能会说,我的服务应该根据该类型的默认值检查属性值。 “bool”的默认值为 false,如果调用我的方法时 bool 属性值为 false,这将破坏我的逻辑。
最佳答案
你的 TrackedValue
类(class)非常准确。但是,您有点重新发明了轮子。这已经被称为 Maybe<T>
单子(monad)。
查看“可能”monad,您会得到很多细节,但这里是:
public class Maybe<T>
{
public readonly static Maybe<T> Nothing = new Maybe<T>();
public T Value { get; private set; }
public bool HasValue { get; private set; }
public Maybe()
{
HasValue = false;
}
public Maybe(T value)
{
Value = value;
HasValue = true;
}
}
它非常像可空类型,但不限于值类型。
所以你可以这样:
class UpdateRequest
{
public int EmployeeId { get; set; }
public Maybe<string> EmployeeName { get; set; }
public Maybe<decimal> Salary { get; set; }
}
例如,如果您只想更新薪水,那么您可以像这样初始化类:
var request = new UpdateRequest()
{
EmployeeId = 1234,
EmployeeName = Maybe<string>.Nothing,
Salary = new Maybe<decimal>(50000m),
};
或者你可以定义一个 .ToMaybe()
像这样的扩展方法:
public static Maybe<T> ToMaybe<T>(this T value)
{
return new Maybe<T>(value);
}
然后初始化看起来像这样:
var request = new UpdateRequest()
{
EmployeeId = 1234,
EmployeeName = Maybe<string>.Nothing,
Salary = 50000m.ToMaybe(),
};
或者你可以像这样添加一个隐式运算符:
public static implicit operator Maybe<T>(T v)
{
return v.ToMaybe();
}
现在初始化更简单了:
var request = new UpdateRequest()
{
EmployeeId = 1234,
EmployeeName = Maybe<string>.Nothing,
Salary = 50000m,
};
然后您应该为类型定义两个“绑定(bind)”运算符 - 即 SelectMany
在 linq 中——像这样:
public static Maybe<U> Select<T, U>(this Maybe<T> m, Func<T, U> k)
{
return m.SelectMany(t => k(t).ToMaybe());
}
public static Maybe<U> SelectMany<T, U>(this Maybe<T> m, Func<T, Maybe<U>> k)
{
if (!m.HasValue)
{
return Maybe<U>.Nothing;
}
return k(m.Value);
}
public static Maybe<V> SelectMany<T, U, V>(this Maybe<T> m, Func<T, Maybe<U>> k, Func<T, U, V> s)
{
return m.SelectMany(x => k(x).SelectMany(y => s(x, y).ToMaybe()));
}
现在您可以针对可能值执行 LINQ 查询。
Maybe<decimal> tax =
from salary in request.Salary
select salary * 0.1m;
然后,如果request.Salary
是Nothing
然后 tax
将是 Nothing
.否则将执行计算。
希望对您有所帮助。
关于c# - .NET 中是否有任何类型指示内部对象是否已初始化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26985177/