有没有办法在C#中强类型化整数ID值?
我最近一直在玩Haskell,并且在应用于ID值时可以立即看到其强类型的优点,例如,您永远不会想要使用PersonId代替ProductId.
有没有一种很好的方法来创建可用于表示给定类型的ID 的Id类/结构?
我有以下想法,但不幸的是,它在许多层面都不合法.您不能拥有抽象结构,并且不会继承隐式/显式转换运算符.
public abstract struct Id
{
int _value;
public Id(int value)
{
_value = value;
}
// define implicit Id to int conversion operator:
public static implicit operator int(Id id)
{
return _value;
}
// define explicit int to Id conversion operator:
public static explicit operator Id(int value)
{
return new Id(value);
}
public bool Equals(object obj)
{
if(GetType() == obj.GetType())
{
Id other = (Id)obj;
return other._value == _value;
}
return false;
}
public int GetHashCode()
{
return _value.GetHashCode();
}
}
struct PersonId : Id { public PersonId(int value) : base(value) {} }
struct ProductId : Id { public ProductId(int value) : base(value) {} }
Run Code Online (Sandbox Code Playgroud)
是否有任何有效的方法来执行类似的操作?我们怎样才能证明整个ID类型不会在大型应用程序中混淆?
mgr*_*ber 21
public interface IId { }
public struct Id<T>: IId {
private readonly int _value;
public Id(int value) {
this._value = value;
}
public static explicit operator int(Id<T> id) {
return id._value;
}
public static explicit operator Id<T>(int value) {
return new Id<T>(value);
}
}
public struct Person { } // Dummy type for person identifiers: Id<Person>
public struct Product { } // Dummy type for product identifiers: Id<Product>
Run Code Online (Sandbox Code Playgroud)
现在你可以使用类型Id<Person>和Id<Product>.的Person和Product类型可以是结构或类.您甚至可以使用由id标识的实际类型,在这种情况下,您不需要任何虚拟类型.
public sealed class Person {
private readonly Id<Person> _id;
private readonly string _lastName;
private readonly string _firstName;
// rest of the implementation...
}
Run Code Online (Sandbox Code Playgroud)
显式运算符重载允许在id类型和底层id值之间安全轻松地进行转换.使用旧接口时,您可能希望将转换为整数更改为隐式,甚至更好,以使用正确类型的版本重载旧接口.当传统接口来自第三方且无法直接更改或过载时,可以使用扩展方法.
public interface ILegacy {
public bool Remove(int user);
}
public static class LegacyExtensions {
public static bool Remove(this ILegacy @this, Id<Person> user) {
return @this.Remove((int)user);
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:添加IId了smartcaveman建议的界面.
编辑:在考虑了Alejandro的建议之后,将两个运算符更改为显式,并添加了如何处理传统接口的部分.