逐字节比较非装箱值类型

Compare non-boxed value type byte-by-byte

提问人:IS4 提问时间:2/28/2016 最后编辑:IS4 更新时间:2/28/2016 访问量:99

问:

.NET(可能是内部的)中是否有一种方法可以比较任何相同类型的任意两个值的相等性,而无需进行任何装箱,并且逐字节比较?我知道有 ,它检查值类型中是否包含任何引用(依次调用)并逐字节比较它们,但您必须将值装箱才能调用此方法。ValueType.EqualsValueType.FastEqualsCheck

我知道我可以通过反射实现这种方法,但由于反射,它仍然会有点慢。FieldInfo.GetValueDirect

该方法应该是泛型的或接受的(就像大多数类似的内部方法一样)。TypedReference

编辑:手动进行比较的不安全方法:

public static class ByteComparer<T> where T : struct
{
    public static readonly Func<T, T, bool> Compare;

    static ByteComparer()
    {
        var t = typeof(T);

        var dyn = new DynamicMethod("Compare", typeof(bool), new[]{t, t}, typeof(ByteComparer<T>));
        var il = dyn.GetILGenerator();

        il.DeclareLocal(t.MakeByRefType(), true);
        il.DeclareLocal(t.MakeByRefType(), true);

        il.Emit(OpCodes.Ldarga_S, 0);
        il.Emit(OpCodes.Stloc_0);
        il.Emit(OpCodes.Ldarga_S, 1);
        il.Emit(OpCodes.Stloc_1);

        il.Emit(OpCodes.Ldloc_0);
        il.Emit(OpCodes.Conv_I);
        il.Emit(OpCodes.Ldloc_1);
        il.Emit(OpCodes.Conv_I);
        il.Emit(OpCodes.Sizeof, t);

        il.EmitCall(OpCodes.Call, typeof(ByteComparer<T>).GetMethod("ByteCompare", BindingFlags.NonPublic | BindingFlags.Static), null);
        il.Emit(OpCodes.Ret);

        Compare = (Func<T,T,bool>)dyn.CreateDelegate(typeof(Func<T,T,bool>));
    }

    private static unsafe bool ByteCompare(byte* a, byte* b, int size)
    {
        for(int i = 0; i < size; i++)
        {
            if(*(a+i) != *(b+i)) return false;
        }
        return true;
    }
}
C# .NET 比较 不安全

评论

0赞 Peter Duniho 2/28/2016
实际上没有任何充分的理由避免将拳击本身作为目标。如果你有一个特定的场景,其中拳击是一个问题,你需要提供一个很好的最小可重现的例子来展示该场景并准确解释问题是什么。就现有的某些方法而言,装箱是在编译器级别处理的;您可以覆盖特定类型或实现,但任何通用方法都可能在某个时候涉及装箱。您是否尝试过自己为该任务编写通用方法?你试过了什么?Equals()IEquatable<T>unsafe
0赞 IS4 2/28/2016
@PeterDuniho 正如我所说,我只是想知道 .NET 是否已经提供了这样的方法。我担心拳击,因为它有轻微的速度问题,也是出于好奇。我知道我可以重写 Equals 并实现 IEquatable(我知道这优于任何其他方法),但我正在寻找一种适用于任何值的通用方法。 方法真的不适用于泛型,如果我没记错的话,没有不安全的字节比较。unsafe
0赞 Peter Duniho 2/29/2016
给定指针,您可以自己编写 memcmp。 适用于任何托管类型都效果不佳,但事实是无论如何您都会遇到问题。您可以发出 IL(如您的示例中所示),或者例如 (即非托管内存块)将托管结构复制到内存中,您可以在其中获取指针并进行比较,这在通用方法中与其他任何地方一样有效。但是:这里可解决的编程问题是什么?您可以像其他人一样查看文档,因此仅询问方法是否存在似乎没有用。真正的问题是什么?byte*unsafeAllocHGlobal()

答: 暂无答案