C# 在C语言中实现幻象类型#

C# 在C语言中实现幻象类型#,c#,C#,我希望使用“幻影类型”来实现类型安全标识符。在F#中这样做有一个问题 我想用C#做这个。怎么做 我有一个解决方案(有问题),所以我将它作为一个可能的答案发布,看看是否有人可以改进它。我提出了以下建议: struct Id<TDiscriminator> { private readonly Guid _id; private Id(Guid id) { _id = id; } public Guid Value {

我希望使用“幻影类型”来实现类型安全标识符。在F#中这样做有一个问题

我想用C#做这个。怎么做


我有一个解决方案(有问题),所以我将它作为一个可能的答案发布,看看是否有人可以改进它。

我提出了以下建议:

struct Id<TDiscriminator>
{
    private readonly Guid _id;

    private Id(Guid id)
    {
        _id = id;
    }

    public Guid Value
    {
        get { return _id; }
    }

    public static Id<TDiscriminator> NewId()
    {
        return From(Guid.NewGuid());
    }

    public static Id<TDiscriminator> From(Guid id)
    {
        return new Id<TDiscriminator>(id);
    }

    public static readonly Id<TDiscriminator> Empty = From(Guid.Empty);

    // Equality operators ellided...
}
public abstract class IdBase
{
    public abstract Guid Value { get; protected set; }

    public static bool operator == (IdBase left, IdBase right)
    {
        return left.Value == right.Value;
    }
}

public sealed class Id<TDiscriminator> : IdBase
{
   // your implementation here, just remember the override keyword for the Value property
}
struct-Id
{
专用只读Guid\u id;
专用Id(Guid Id)
{
_id=id;
}
公共Guid值
{
获取{return\u id;}
}
公共静态Id NewId()
{
从(Guid.NewGuid())返回;
}
来自的公共静态Id(Guid Id)
{
返回新Id(Id);
}
公共静态只读Id Empty=From(Guid.Empty);
//省略相等运算符。。。
}
…我可以按如下方式使用:

class Order { /* empty */ }
class Customer { /* empty */ }

void Foo()
{
    var orderId = Id<Order>.NewId();
    var customerId = Id<Customer>.NewId();

    // This doesn't compile. GOOD.
    bool same = (orderId == customerId);
}
类顺序{/*empty*/}
类客户{/*空*/}
void Foo()
{
var orderId=Id.NewId();
var customerId=Id.NewId();
//这不能编译,很好。
bool same=(orderId==customerId);
}
我并不特别想要鉴别器的具体类,因为我不希望任何人实例化它们

我可以通过使用接口或抽象类来解决这个问题。不幸的是,这些仍然可以派生并实例化


C#不会让你用电话的。我不能说我对这个问题的答案完全满意,因为答案基本上是“仅仅因为”。

为什么不让它成为一个具有私有构造函数的密封类

public sealed class Id<TDiscriminator>
{
    private Id() { }

    //some static methods
}
公共密封类Id
{
私有Id(){}
//一些静态方法
}

就我所知,您希望提供一种通过自定义标识符对象来区分不同类型的机制。我认为你已经接近一个可行的解决方案了。在.NET中,当具有泛型类时,泛型参数的每次替换(或者泛型参数的每个唯一组合,如果不止一个)都会在运行时创建一个唯一的类型。在代码中,
Id
Id
是两种不同的类型。
NewId()。这两种类型没有实现
==
运算符,因此无法进行比较。此外,这种比较很难实现,因为您无法确定
Id
的所有可能用途-您无法猜测将用什么类型的
TDsicriminator
替代

1. 一个快速而简单的解决方案是:

class Order { /* skipped */ }
class Customer { /* skipped */ }

void Foo()
{
    var orderId = Id<Order>.NewId();
    var customerId = Id<Customer>.NewId();

    bool sameIds = (orderId.Value == customerId.Value); // true
    bool sameObjects = orderId.Equals(customerId); // false
}
但是,许多人不推荐第二种方法,因为
IdBase
的不同实现可能恰好具有相同的
Value
属性(如果使用传递现有ID的构造函数)。例如:

var guid = Guid.NewGuid();
var customerID = Id<Customer>.From(guid);
var orderID = Id<Order>.From(guid);
请注意此处使用的
关键字中的
。这适用于.NET4.0,其中泛型可以是协变的,并确保类使用逆变泛型。(见附件)。在上面的代码中,_idStatic字段对于作为泛型参数提供的每个不同类型都有一个唯一的值

我希望这些信息对你有帮助。

怎么样

public sealed class Order
{
    private Order() {}
}

public static sealed class Id<T>
{
    // ...
}
公共密封类命令
{
私人订单(){}
}
公共静态密封类Id
{
// ...
}

我想那正是你说的。没有人(除了一些特殊情况)可以构造它,也没有人可以继承它。

好吧,我希望Id类是密封的,真的。更重要的是,在我的回答中,鉴别器不应该是一个真正困扰我的“类”。如果它不是一个类(它是一个值类型),那将是一个麻烦,因为值类型总是可以实例化的。如果我理解正确的话。问题在于订单和客户类。可以将它们设置为引用类型,因为它们只是要传递的某种标记,以代替类型来区分不同的Id。关于静态类的使用,你可以添加一个空的私有构造函数(显然没有其他构造函数),这将阻止任何子类。要输入的字符还多一些,但仍然合理。
public sealed class Order
{
    private Order() {}
}

public static sealed class Id<T>
{
    // ...
}