3 回答
TA贡献1812条经验 获得超5个赞
首先,这是一个非常好的主意。一个简短的旁白:
我希望 C# 能够更轻松地围绕整数、字符串、id 等创建廉价的类型化包装器。作为程序员,我们非常“字符串快乐”和“整数快乐”;很多东西都表示为字符串和整数,可以在类型系统中跟踪更多信息;我们不想将客户名称分配给客户地址。不久前,我写了一系列关于在 OCaml 中编写虚拟机的博客文章(从未完成!),我所做的最好的事情之一就是将虚拟机中的每个整数都包装成一个表明其用途的类型。这防止了这么多的错误!OCaml 使得创建小包装器类型变得非常容易;C# 没有。
其次,我不会太担心重复代码。它主要是一个简单的复制粘贴,你不太可能编辑代码或犯错误。花时间解决实际问题。一点点复制粘贴的代码没什么大不了的。
如果您确实想避免复制粘贴的代码,那么我建议您使用这样的泛型:
struct App {}
struct Payment {}
public struct Id<T>
{
private readonly Guid _value;
public Id(string value)
{
var val = Guid.Parse(value);
CheckValue(val);
_value = val;
}
public Id(Guid value)
{
CheckValue(value);
_value = value;
}
private static void CheckValue(Guid value)
{
if(value == Guid.Empty)
throw new ArgumentException("Guid value cannot be empty", nameof(value));
}
public override string ToString()
{
return _value.ToString();
}
}
现在你完成了。您有类型Id<App>andId<Payment>而不是AppIdand PaymentId,但您仍然不能分配Id<App>to Id<Payment>or Guid。
此外,如果您喜欢使用AppId,PaymentId然后在文件顶部,您可以说
using AppId = MyNamespace.Whatever.Id<MyNamespace.Whatever.App>
等等。
第三,您可能需要在您的类型中添加更多功能;我认为这还没有完成。例如,您可能需要相等,以便检查两个 id 是否相同。
第四,请注意,它default(Id<App>)仍然会给您一个“空 guid”标识符,因此您阻止它的尝试实际上不起作用;仍然可以创建一个。没有真正的好办法。
TA贡献1802条经验 获得超5个赞
这有一个很好的副作用。您可以将这些重载用于添加:
void Add(Account account);
void Add(Payment payment);
但是,您不能对 get 进行重载:
Account Get(Guid id);
Payment Get(Guid id);
我一直不喜欢这种不对称。你所要做的:
Account GetAccount(Guid id);
Payment GetPayment(Guid id);
使用上述方法,这是可能的:
Account Get(Id<Account> id);
Payment Get(Id<Payment> id);
达到对称。
- 3 回答
- 0 关注
- 134 浏览
添加回答
举报