如何使用固定的Array或T []类型的变量?

usr*_*usr 5 c# unsafe fixed

我正在研究一个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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

固定语句不允许我固定ArrayT[].

有错误消息是:

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')
Run Code Online (Sandbox Code Playgroud)

现在,我实际上并不关心我是如何完成这项工作的(我并没有采用这种方法).我怎么能memcmp2 T[],我知道,T是一个原始/ blittable类型?

我真的想避免切换类型并为每个有趣的类型创建一个专门的(和重复的)代码版本.由于性能限制,任何类型的反射解决方案都是不可行的(是的,我真的需要这里的性能 - 没有过早的优化警告适用,因为它是Stack Overflow的惯例).

Han*_*ant 5

我知道T是原始/ blittable类型

你知道,编译器不知道.CLR要求垃圾收集器不再移动固定对象中的所有内容.对于包含其数组元素的Array.只有符合条件的T才是一种简单的值类型,一种是blittable.泛型并没有给你一种方法来将T限制为一个blittable类型.

您通常将memcmp()的参数声明为byte [].然后pinvoke marshaller已经做了正确的事情,并在调用memcmp()之前固定byte []数组.然而,这也不起作用,因为你不能轻易地将T []转换为字节[].你必须用GCHandle固定自己.相应地将memcmp()参数声明为IntPtr而不是byte [].

可以工作的类型子集在实践中足够小,可以考虑简单地编写方法重载而不是通用方法.现在,pinvoke marshaller可以处理钉扎,相应地重载memcmp()函数声明.