Tom*_*bes 39 c# generics struct guid
我已经在代码中制作了两次相同的bug,如下所示:
void Foo(Guid appId, Guid accountId, Guid paymentId, Guid whateverId)
{
...
}
Guid appId = ....;
Guid accountId = ...;
Guid paymentId = ...;
Guid whateverId =....;
//BUG - parameters are swapped - but compiler compiles it
Foo(appId, paymentId, accountId, whateverId);
Run Code Online (Sandbox Code Playgroud)
好的,我想防止这些错误,所以我创建了强类型的GUID:
[ImmutableObject(true)]
public struct AppId
{
private readonly Guid _value;
public AppId(string value)
{
var val = Guid.Parse(value);
CheckValue(val);
_value = val;
}
public AppId(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();
}
}
Run Code Online (Sandbox Code Playgroud)
还有另一个PaymentId:
[ImmutableObject(true)]
public struct PaymentId
{
private readonly Guid _value;
public PaymentId(string value)
{
var val = Guid.Parse(value);
CheckValue(val);
_value = val;
}
public PaymentId(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();
}
}
Run Code Online (Sandbox Code Playgroud)
这些结构几乎相同,有很多重复的代码.不是吗?
除了使用class而不是struct之外,我无法找出解决它的任何优雅方法.我宁愿使用struct,因为空检查,更少的内存占用,没有垃圾收集器开销等...
你有一些想法如何使用struct而不重复代码?
Eri*_*ert 45
首先,这是一个非常好的主意.简要说一下:
我希望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();
}
}
Run Code Online (Sandbox Code Playgroud)
现在你已经完成了.你有类型的Id<App>和Id<Payment>,而不是AppId和PaymentId,但你仍然不能分配Id<App>给Id<Payment>或Guid.
此外,如果您喜欢使用AppId,PaymentId然后在文件的顶部,您可以说
using AppId = MyNamespace.Whatever.Id<MyNamespace.Whatever.App>
Run Code Online (Sandbox Code Playgroud)
等等.
第三,您可能需要更多类型的功能; 我认为这还没有完成.例如,您可能需要相等,以便您可以检查两个ID是否相同.
第四,要注意default(Id<App>)仍然会给你一个"空guid"标识符,所以你试图阻止它实际上不起作用; 它仍然可以创建一个.这并不是一个好方法.
| 归档时间: |
|
| 查看次数: |
1045 次 |
| 最近记录: |