盲目地将结构转换为类以隐藏默认构造函数?
-
07-07-2019 - |
题
我阅读了与该主题相关的所有问题,它们都给出了为什么默认构造函数的原因 struct
在 C# 中不可用,但我还没有找到任何人在遇到这种情况时提出一般行动方案。
显而易见的解决方案是简单地转换 struct
到一个 class
并处理后果。
还有其他选择可以将其保留为 struct
?
我在使用我们的一个内部商务 API 对象时遇到了这种情况。设计师将其改造成 class
到一个 struct
, ,现在默认构造函数(之前是私有的)使对象处于无效状态。
我想如果我们要把这个物体保留为 struct
, ,应该引入一种检查状态有效性的机制(类似于 IsValid
财产)。我遇到了很大的阻力,并且对“使用 API 的人不应该使用默认构造函数”的解释无疑引起了我的注意。(笔记:有问题的对象是通过静态工厂方法“正确”构造的,并且所有其他构造函数都是 internal
.)
每个人都只是简单地转换他们的 struct
到 class
在这种情况下不加思考?
编辑:我想看到一些关于如何将这种类型的对象保留为 struct
——上面提到的对象更适合作为 struct
比作为 class
.
解决方案
为一个 struct
, ,您设计类型,以便默认构造的实例(字段全为零)是有效状态。你不[最好不要] 任意使用 struct
代替 class
没有充分的理由 - 使用不可变引用类型没有任何问题。
我的建议:
- 确保使用的原因
struct
是有效的([真实的]分析器揭示了由于大量分配非常轻量级的对象而导致的严重性能问题)。 - 设计类型以使默认构造的实例有效。
- 如果类型的设计由本机/COM 互操作约束决定,则包装功能并且不要公开
struct
在包装器外部(私有嵌套类型)。这样您就可以轻松记录并验证约束类型要求的正确使用。
其他提示
原因是 CLR 对结构体(System.ValueType 的实例)进行了特殊处理:它被初始化为所有字段都为 0(或默认值)。您实际上甚至不需要创建一个 - 只需声明它即可。这就是为什么需要默认构造函数。
您可以通过两种方式解决这个问题:
- 创建一个像 IsValid 这样的属性来指示它是否是有效的结构,就像您指示的那样
- 在 .Net 2.0 中,考虑使用 Nullable<T> 来允许未初始化(null)的结构。
将结构更改为类可能会产生一些非常微妙的后果(在内存使用和对象标识方面,这在多线程环境中出现得更多),并且对于未初始化的对象来说,虽然不那么微妙,但很难调试 NullReferenceExceptions。
下面的表达式说明了无法定义默认构造函数的原因:
new MyStruct[1000];
这里有 3 个选项
- 调用默认构造函数 1000 次,或者
- 创建损坏的数据(请注意,结构可以包含引用;如果您不初始化或清空引用,则可能会访问任意内存),或者
- 将分配的内存清零(在字节级别)。
.NET 对结构和类执行相同的操作:字段和数组元素用零空白。这也使结构和类之间的行为更加一致,并且没有不安全的代码。它还允许 .NET 框架不专门化类似的东西 new byte[1000]
.
这是 .NET 结构体的默认构造函数,它会自行处理:将所有字节清零。
现在,要解决这个问题,您有几个选择:
- 将 Am-I-Initialized 属性添加到结构中(例如
HasValue
在Nullable
). - 允许清零的结构为有效值(例如 0 是小数的有效值)。