在C#中强烈键入ID值 [英] Strongly typing ID values in C#

查看:37
本文介绍了在C#中强烈键入ID值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法在C#中强烈键入整数ID值?

Is there a way to strongly type integer ID values in C#?

我最近一直在玩Haskell,并且可以立即看到Haskell在应用于ID值时具有强类型化的优点,例如,您永远不想使用 PersonId 代替 ProductId .

I've recently been playing with Haskell and can immediately see the advantages of its strong typing when applied to ID values, for example you would never want to use a PersonId in place of a ProductId.

是否有一种很好的方法来创建可用于表示给定类型ID的 Id 类/结构?

Is there a nice way to create an Id class/struct that can be used to represent IDs of a given type?

我有以下想法,但不幸的是,在许多层面上,它不合法.您不能具有抽象结构,并且隐式/显式强制转换运算符也不会被继承.

I had the following idea but unfortunately it isn't legal on many levels. You can't have an abstract struct and the implicit/explicit cast operators wouldn't be inherited.

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) {} }

是否存在执行类似操作的有效方法?我们还能如何证明整数ID类型不会在大型应用程序中混淆?

Are there any valid ways to perform something similar? How else can we prove that integer IDs type aren't being confused across a large application?

推荐答案

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>

现在,您可以使用类型 Id< Person> Id< Product> . Person Product 类型可以是结构或类.您甚至可以使用由ID标识的实际类型,在这种情况下,您不需要任何虚拟类型.

Now you can use types Id<Person> and Id<Product>. The Person and Product types can be either structs or classes. You can even use the actual types that are identified by the id and in that case you do not need any dummy types.

public sealed class Person {
    private readonly Id<Person> _id;
    private readonly string _lastName;
    private readonly string _firstName;

    // rest of the implementation...
}

显式运算符重载允许在id类型和基础id值之间安全且容易地进行强制转换.在使用旧版接口时,您可能需要将强制转换更改为整数,以使其隐式甚至更好,以便使用适当类型的版本使旧版接口过载.当旧版接口来自第三方且无法直接更改或重载时,可以使用扩展方法.

The explicit operator overloads allow safe and easy casting between id types and underlying id values. When working with legacy interfaces you may want to change the casting to integer to be implicit, or even better, to overload the legacy interfaces with properly typed versions. Extension methods can be used when the legacy interface is from a third party and cannot be changed or overloaded directly.

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);
    }
}

根据smartcaveman的建议,添加了 IId 界面.

Added IId interface as suggested by smartcaveman.

编辑:在考虑了Alejandro的建议后将两个运算符都更改为明确的,并增加了如何处理旧版界面的部分.

Changed both operators to be explicit after thinking about Alejandro's suggestion and added a section how to deal with legacy interfaces.

这篇关于在C#中强烈键入ID值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆