gpt4 book ai didi

c# - 判断一个结构体是否为没有 "Equals"的默认值;也称为结构的 ReferenceEquals

转载 作者:太空狗 更新时间:2023-10-29 21:30:10 29 4
gpt4 key购买 nike

对于我正在编写的一些通用辅助方法,我希望能够在该值是其类型的默认值时调用特殊处理。对于引用类型,这很简单——默认值为 null。我不能使用泛型类型参数,尽管我可以解决这个问题。

我可以这样做:

public bool DetectPossiblyUninitializedValue(object val) {
return val== null ||
val.GetType().IsValueType
&& Equals(val, Activator.CreateInstance(val.GetType());
}

这就是我现在正在使用的,但这取决于 Equals 的实现。这很好,但并不理想。特别是,某些实现可能会覆盖 Equals 以在正常情况下支持更多可用的语义。在这里将默认值视为特殊值实际上并不少见,因为默认初始化在 .NET 中是不可避免的。

但是,在这种情况下,我只想知道对象是否可能已经初始化,因此我不想要任何自定义相等性或其他任何东西。基本上,我想知道 struct 占用的内存区域是否在初始化后由 VM 保证填充为零,仅此而已。从某种意义上说,我正在为结构寻找类似于 ReferenceEquals 的东西:一种忽略底层对象自身实现的比较。

如何在不使用 Equals 的情况下比较原始结构值?我可以比较原始结构值吗?

编辑: 我正在使用它来连接类+结构,这些类+结构代表领域特定的概念,这些概念通过本质上代表各种业务规则的任意代码连接到 GUI。一些旧代码基本上处理可能嵌套的字符串字典到任意对象,因此需要一堆未经检查的强制转换或动态;创建这些很容易出错。所以能够相对直接地使用类型化对象是件好事。另一方面,GUI 和包装代码以不同方式处理可能未初始化的值是有用的;虽然逐个案例、逐个类型的解决方案是可能的,但那是很多代码;合理的默认值很有用。我真正想要的是一种自动生成与另一个类型相同但所有属性/公共(public)字段都扩展为包含“未初始化”值的类型的方法,但这不是期望的现实功能 - 相比之下,在动态世界中这将是虽然在其他地方没有类型安全,但很容易实现......

答案: Mehrdad 在 how to directly access the bits of structs 上发布了一个答案;我添加了 an implementation using that to detect possibly uninitialized values .

最佳答案

如果您担心装箱的开销(并且您已经测量这是一个瓶颈),您可以用不同的方式解决它:

为您的结构创建两个临时盒装实例作为一个对象,它可以被所有结构重用。使用 Reflection.Emit,创建一个使用 Unbox 的方法将结构复制 到盒装版本的操作码。 (这可以让您避免分配。)对另一个装箱结构执行相同的操作,然后对对象调用 Equals


备注:

我不知道委托(delegate)调用的开销是否真的更快,但无论如何您都可以试试看。如果您发现它不是,那么您总是可以同时进行多个比较——传入一个数组或其他东西。它变得复杂,但如果您知道这是瓶颈,那么它可能是值得的,具体取决于您的struct有多大。


黑客解决方案:

我不是支持这个解决方案,只是暗示它存在。 如果您不知道它在做什么,请不要使用它。

bool UnsafeHackyEquals<T>(ref T a, ref T b) where T : struct
{
TypedReference pA = __makeref(a), pB = __makeref(b);
var size = SizeOf<T>();
IntPtr* ppA = (IntPtr*)&pA, ppB = (IntPtr*)&pB;
//Now ppA[0] is a pointer to a, and ppB[0] is a pointer to b.
//You have the size of both, so you can do a bitwise comparison.
}

要查找结构的大小:

static class ArrayOfTwoElements<T> { static readonly T[] Value = new T[2]; }

static uint SizeOf<T>()
{
unsafe
{
TypedReference
elem1 = __makeref(ArrayOfTwoElements<T>.Value[0] ),
elem2 = __makeref(ArrayOfTwoElements<T>.Value[1] );
unsafe
{ return (uint)((byte*)*(IntPtr*)(&elem2) - (byte*)*(IntPtr*)(&elem1)); }
}
}

是的,它有点没有记录。但是,如果您担心这一点,您可以只发出 这个方法(因为确实记录了 MkRefAny 操作码),所以这不是问题。然而,这个例子在其他平台上可能会失败,所以要小心......

关于c# - 判断一个结构体是否为没有 "Equals"的默认值;也称为结构的 ReferenceEquals,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6427861/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com