【问题标题】:Is there a way I can prevent struct from being insantiated or can I have a class that will be copied?有没有办法可以防止 struct 被实例化,或者我可以有一个将被复制的类?
【发布时间】:2013-02-04 07:31:46
【问题描述】:

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

假设我有这个课程:

public sealed class Entity
{
    int value;

    Entity()
    {

    }

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

我不希望这个类在类之外被实例化,这很有效。但是这里Entitys 将被引用而不是像值类型一样被复制。这个类太小了,我希望它表现得像值类型。另外,如果我比较Entitys 的两个实例,例如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

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

【问题讨论】:

  • 您的意思是没有覆盖类上的“Equals”方法或“==”运算符来执行所需的比较?
  • @DavidW 是的,这是可能的。但它仍然不会为类提供值类型语义,或者换句话说,我的要求 1。

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


【解决方案1】:

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

你的选择是要么

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

我的建议是使用一个类,直到您发现存在性能问题。

【讨论】:

    【解决方案2】:

    一个类型对于该类型的存储位置会发生什么没有发言权。任何类型的存储位置都可以存在,或者它们的内容被相同类型的其他位置的内容覆盖,而类型本身对此事没有任何发言权。引用类型的存储位置保存类引用;当它存在时,它将是一个空引用。引用类型的存储位置保存空引用以外的任何内容的唯一方法是,如果创建了该类型的实例并且——在某些涉及完全信任代码和反射的场景之外——引用类型将完全控制可能发生这种情况的情况。

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

    我建议创建一个具有类类型的单个私有字段的结构。您不能阻止代码创建default(Entity),但这并不意味着您必须允许代码对它做任何有用的事情。它的Equals 方法应该工作得很好,可以在与另一个默认实例比较时返回true,在与其他任何实例比较时返回false,并且GetHashCode 应该为所有默认实例返回相同的值,但任何其他方法都可以抛出异常。

    【讨论】:

    • 如果我有类类型的私有支持字段,它会给我带来什么好处?结构仍然是可实例化的。我会遗憾地采用我原来的方法(贾斯汀的回答)。
    • @nawfal:将类包装在结构中允许您公开与类本身公开的不同的方法,还允许您控制默认实例的行为。任何人都可以创建任何类型的变量——类或结构——并调用传递该变量的方法。在类类型的情况下,默认值变量将比较等于null,并且尝试调用任何方法都会抛出NullReferenceException。使用结构体,您可以决定方法应该对默认实例产生什么影响。
    【解决方案3】:

    Entity 制作所有构造函数(除了静态构造函数)privateprotected 也可以,但因为它是sealed,所以没有多大意义。

    【讨论】:

    • 你似乎没有得到我的问题。将构造函数设为私有使其不可实例化,但它是否符合我的要求 1?没有..
    • 为什么不直接覆盖Equals
    • 是的,这是可能的,但它仍然是引用类型,而不是值类型,否则将被复制。我将编辑我的问题。
    猜你喜欢
    • 1970-01-01
    • 2020-11-02
    • 1970-01-01
    • 1970-01-01
    • 2021-12-03
    • 1970-01-01
    • 1970-01-01
    • 2021-10-05
    • 1970-01-01
    相关资源
    最近更新 更多