C# 中的幻像泛型约束

Phantom generic constraints in C#

我经常遇到这个问题:我喜欢为不同的 return 类型重载一些具有相同参数的方法,但 .NET 拒绝对密封 classes/primitives 的通用约束。我将此模式称为 phantom generics.

  • 我知道一个丑陋的解决方法:将类型实现的每个接口都放在 where 语句后面。

  • 我的问题:有什么方法可以在泛型中使用显式类型来说明 return 类型并保持方法不同?

    这是我的代码:

    public static class Reinterpret {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static unsafe float Cast<T>(int value) where T : float { //'float' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
            return *((float*)&value); //reinterpret the bytes of 'value' to a float
        }
    
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static unsafe float Cast<T>(uint value) where T : float { //'float' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
            return *((float*)&value);
        }
    
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static unsafe double Cast<T>(long value) where T : double { //'double' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
            return *((double*)&value);
        }
    
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static unsafe double Cast<T>(ulong value) where T : double { //'double' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
            return *((double*)&value);
        }
    }
    
  • 这是一种稍微不同的方法:

    // Constraints just to be vaguely reasonable.
    public static class Reinterpret<T> where T : struct, IComparable<T>
    {
        public T Cast(int value) { ... }
        public T Cast(uint value) { ... }
        public T Cast(float value) { ... }
        public T Cast(double value) { ... }
        // etc       
    }
    

    对于 实现 ,你可以有一个 Func<int, T> 字段,一个 Func<double, T> 字段等,然后有一个大的静态构造函数:

    static Reinterpret()
    {
        if (typeof(T) == typeof(int))
        {
            // Assign all the fields using lambda expressions for ints.
            // The actual assignment might be tricky, however - you may
            // need to resort to some ghastly casting, e.g.
            castDouble = (Func<double, T>)(Delegate)(Func<double, int>)
                x => *((double*)&value;
        }
        ....
    }
    

    然后对于您不想支持的任何类型,字段将为空。每个 Cast 方法看起来像:

    if (castIntMethod != null)
    {
        return castInt(value);
    }
    throw new InvalidOperationException("...");
    

    老实说,这不是我真正想做的事情。我通常只使用 BitConverter。但这是一个选项

    泛型不是模板。它们不像模板。不能使它们像模板一样工作。

    "phantom" 通用参数不会帮助您模拟模板(无论如何 reinterpret_cast 不是实际模板),因为您很快就会 运行事实上 泛型不支持专业化

    特别是,您问 "Is there any way to use explicit types in generics to ... keep methods distinct?" 并评论说 "the generic constraints ... keeps [sic] the methods distinct"。但他们实际上没有。这些方法之所以不同,只是因为参数类型不同。泛型是从重载中计算出来的,它们不影响重载。