有没有办法可以阻止struct被实例化,或者我可以拥有一个将被复制的类?

时间:2013-02-19 14:58:24

标签: c# reference struct value-type default-constructor

好的,这比实际要求更有好奇心。

假设我有这门课程:

public sealed class Entity
{
    int value;

    Entity()
    {

    }

    public static implicit operator Entity(int x)
    {
        return new Entity { value = x };
    }
}

我不希望这个类在类之外被实例化,这是有效的。但是这里Entity将被引用,而不是像值类型那样被复制。这个类很小我希望它表现得像值类型。此外,如果我比较Entity的两个e1 == e2实例,它将提供引用相等(好吧我可以重载==,但这更有用)。所以我会把它变成一个结构:

public struct Entity
{
    int value;

    public static implicit operator Entity(int x)
    {
        return new Entity { value = x };
    }
}

但现在有人可以轻松地new Entity()

我的问题是我可以使用

类型(结构/类) 每次访问该值时都会复制

1),以便

Entity e1 = 1;
Entity e2 = e1;
ReferenceEquals(e1, e2); // prints false, just like any value type

2)在比较相等时具有值语义

Entity e1 = 1;
Entity e2 = 1;
e1.Equals(e2); // prints true

// this is easy though by overriding default equality.

3)在类型范围之外不可实例化:

Entity e = new Entity(); // should not compile

基本上接近枚举的行为。我当然可以没有它,只是学习。

3 个答案:

答案 0 :(得分:2)

不可能重新定义或尝试隐藏C#中结构的默认构造函数,因为C#编译器会根据无参数构造函数不执行任何操作的惯例来编译代码。请参阅Why can't I define a default constructor for a struct in .NET?

您的选择是

  • 使用课程
  • 确保结构的默认值具有某种含义(例如,在您的情况下,int将初始化为0) - 这就是枚举所做的(回想一下枚举初始化为0)。

我的建议是在确定存在性能问题之前使用一个类。

答案 1 :(得分:1)

类型对该类型的存储位置可能发生的情况没有发言权。任何类型的存储位置都可以存在,或者其内容被相同类型的其他位置的内容覆盖,而该类型本身在该问题上没有任何发言权。引用类型的存储位置包含类引用;当它存在时,它将是一个空引用。引用类型的存储位置将保留除空引用之外的任何内容的唯一方法是,如果创建了该类型的实例,并且 - 在某些涉及完全信任代码和反射的方案之外 - 引用类型将完全控制可能发生的情况。

相比之下,值类型的存储位置是该类型的实例。因此,结构无法控制一个人如何存在。结构可以控制的程度 - 在有限程度上 - 是其字段可以包含的值。在有限的信任场景中,如果结构的代码将该值写入结构的某个实例(如果该值被写入结构的任何实例,甚至是有限信任代码),则私有结构字段只能采用非默认值。访问该实例可能能够使用多线程重叠读取和写入来生成具有组合字段值的结构,结构本身永远不会创建它们。)

我建议使用类类型的单个私有字段创建结构。您无法阻止代码创建default(Entity),但这并不意味着您必须允许代码对其执行任何有用的操作。与其他默认实例进行比较时,其Equals方法应该可以正常运行以返回true,与其他任何内容进行比较时,falseGetHashCode应返回相同的值默认实例,但任何其他方法都可能抛出异常。

答案 2 :(得分:-1)

private创建所有构造函数(除了静态构造函数)Entityprotected也可以使用,但是从sealed起,这没有多大意义。