我正在开发一个 IEqualityComparer
,它可以非常快速地比较基本类型的数组。我的计划是获取指向数组的指针并 memcmp
它们。像这样:
public unsafe override bool Equals(T[] x, T[] y)
{
if (ReferenceEquals(x, y)) return true;
if (x == null || y == null) return false;
if (x.Length != y.Length) return false;
var xArray = (Array)x;
var yArray = (Array)y;
fixed (void* xPtr = xArray) //compiler error 1
fixed (T* yPtr = y) //compiler error 2
{
return memcmp(xPtr, yPtr, x.Length * this.elementSize);
}
}
fixed 语句不允许我固定 Array
或 T[]
。
错误信息是:
1. Cannot implicitly convert type 'System.Array' to 'void*'
2. Cannot take the address of, get the size of, or declare a pointer to a managed type ('T')
现在,我实际上并不关心我是如何完成这项工作的(我不致力于这种确切的方法)。我如何memcmp
两个 T[]
我知道 T
是原始/blittable 类型?
我真的想避免切换类型并为每个有趣的类型创建专门的(和重复的)代码版本。由于性能限制,任何类型的反射解决方案都不可行(是的,我真的需要这里的性能 - 没有过早的优化警告适用,因为它在 Stack Overflow 上是习惯的)。
最佳答案
where I know that T is a primitive/blittable type
你知道,编译器不知道。 CLR 要求固定对象中的所有 不能再被垃圾收集器移动。对于一个数组,它包括它的数组元素。唯一符合条件的 T 是一种简单值类型,blittable。泛型不会为您提供将 T 限制为可 blittable 类型的方法。
您通常会将 memcmp() 的参数声明为 byte[]。然后 pinvoke 编码器已经做了正确的事情,并会在调用 memcmp() 之前固定 byte[] 数组。但是,这也不起作用,因为您也无法轻松地将 T[] 转换为 byte[]。您必须将自己固定在 GCHandle 上。相应地将 memcmp() 参数声明为 IntPtr 而不是 byte[]。
实际上可以工作的类型子集足够小,可以考虑简单地编写方法重载而不是泛型方法。现在使 pinvoke 编码器能够处理固定,相应地重载 memcmp() 函数声明。
关于c# - 如何将 fixed 与 Array 或 T[] 类型的变量一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14833218/