C#中的幻像通用约束

时间:2015-03-05 21:15:48

标签: c# generics phantom-types

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

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

  • 我的问题:有没有办法在泛型中使用显式类型来说明返回类型并保持方法不同?

    这是我的代码:

    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);
        }
    }
    
  • 2 个答案:

    答案 0 :(得分:7)

    这是一种略微不同的接近方式:

    // 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;
        }
        ....
    }
    

    然后,对于您不想支持的任何类型,字段将为null。每个Cast方法都如下所示:

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

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

    答案 1 :(得分:6)

    泛型不是模板。它们不像模板那样。它们不能像模板一样。

    “幻影”通用参数无法帮助您模拟模板(并且reinterpret_cast不是真正的模板,无论如何),因为您很快就会遇到泛型不会支持专业化

    特别是,你问过“有没有办法在泛型中使用显式类型来保持方法的独特性?”并评论说“通用约束......保持[原文如此不同的方法”。但他们实际上并没有。这些方法之所以不同,只是因为参数类型不同。泛型是根据重载计算的,它们不会影响重载。