如何从无符号类型泛型参数派生签名类型,反之亦然?

时间:2018-03-16 10:50:00

标签: c# .net generics integer .net-core

我想制作ToSigned,ToUnsinged的通用方法 这就是我所拥有的

public static class Number<T> {

// public static bool IsSigned = MinValue.Equals(0) ? false : true;
// public static bool IsUnsigned = MinValue.Equals(0) ? true : false;

public static object ToUnsigned(T input)
{
    if (IsUnsigned)
        return input;

    // T is Signed 
    // How to derive unsigned type from signed type ? 
    // return SignedToUnsigned<T, unsigned T>(input);
    return null;
}


public static object ToSigned(T input)
{
    if (IsSigned)
        return input;

    // T is Unsigned 
    // How to derive signed type from unsigned type ? 
    // return UnsignedToSigned<T, signed T> (input);
    return null;
}


}

我已经成功实现了SignedToUnsigned和UnsignedToSigned,但是如何从无符号类型派生签名类型,或从签名类型派生无符号类型?

2 个答案:

答案 0 :(得分:0)

这没有内置机制;您必须根据comment.content.title

对其进行硬编码
T

现在重复所有预期的类型。

请注意,这并不像它看起来那么昂贵,因为对于值类型if(typeof(T) == typeof(int)) return new Number<uint>( (uint)((Number<int>)value).Value); // or similar if(typeof(T) == typeof(long)) return new Number<ulong>( (ulong)((Number<long>)value).Value); // or similar ,JIT每个T发生一次,而JIT可以根据它删除分支常量包括T

我想知道,更好的选择是否是特定 typeof(T)的扩展方法:

T

答案 1 :(得分:0)

内置无法做到这一点。
另请注意,Equals会检查它是否是相同的对象,而不是相同的值,因此(IsSigned,IsUnsigned)的结果是错误的。

您可以使用词典手动映射类型(或使用if语句,因为只有4种整数类型),然后使用反射调用您的方法:

但是如果你使用ifs和强制转换,并且在没有反射的情况下使用它,那么速度会明显加快。

public static class Number<T>
    where T:System.IComparable
{

    public static bool IsSigned = MinValue.CompareTo(default(T)) == 0 ? false : true;

    public static bool IsUnsigned = MinValue.CompareTo(default(T)) == 0 ? true : false;



    private static System.Collections.Generic.Dictionary<System.Type, System.Type> MapSignedUnsigned
            = TypeMapSignedToUnsigned();


    private static System.Collections.Generic.Dictionary<System.Type, System.Type> MapUnsignedSigned
            = TypeMapUnsignedToSigned();


    private static System.Collections.Generic.Dictionary<System.Type, System.Type>
        TypeMapSignedToUnsigned()
    {
        System.Collections.Generic.Dictionary<System.Type, System.Type> dict
            = new System.Collections.Generic.Dictionary<System.Type, System.Type>();

        dict.Add(typeof(System.SByte), typeof(System.Byte));
        dict.Add(typeof(System.Int16), typeof(System.UInt16));
        dict.Add(typeof(System.Int32), typeof(System.UInt32));
        dict.Add(typeof(System.Int64), typeof(System.UInt64));

        return dict;
    }


    private static System.Collections.Generic.Dictionary<System.Type, System.Type>
        TypeMapUnsignedToSigned()
    {
        System.Collections.Generic.Dictionary<System.Type, System.Type> dict
            = new System.Collections.Generic.Dictionary<System.Type, System.Type>();

        dict.Add(typeof(System.Byte), typeof(System.SByte));
        dict.Add(typeof(System.UInt16), typeof(System.Int16));
        dict.Add(typeof(System.UInt32), typeof(System.Int32));
        dict.Add(typeof(System.UInt64), typeof(System.Int64));

        return dict;
    }


    public static T2 ToUnsigned<T2>(T input)
    {
        if (IsUnsigned)
            return (T2) (object) input;

        // T is Signed 
        // t is unsigned type for T 
        System.Type t = MapSignedUnsigned[typeof(T)];

        // TUnsigned SignedToUnsigned<TSigned, TUnsigned>(TSigned longValue)
        // return SignedToUnsigned<T, t> (input);
        System.Reflection.MethodInfo method = typeof(Number<T>).GetMethod("SignedToUnsigned");
        System.Reflection.MethodInfo genericMethod = method.MakeGenericMethod(typeof(T), t);

        return (T2) genericMethod.Invoke(null, new object[] { input });
    }


    public static T2 ToSigned<T2>(T input)
    {
        if (IsSigned)
            return (T2) (object) input;

        // T is Unsigned 
        // t is signed type for T 
        System.Type t = MapUnsignedSigned[typeof(T)];
        // TSigned UnsignedToSigned<TUnsigned, TSigned>(TUnsigned ulongValue)
        // return UnsignedToSigned<T, t> (input);
        System.Reflection.MethodInfo method = typeof(Number<T>).GetMethod("UnsignedToSigned");
        System.Reflection.MethodInfo genericMethod = method.MakeGenericMethod(typeof(T), t);

        return (T2)genericMethod.Invoke(null, new object[] { input });
    }


}

为什么不使用对象而不是泛型,例如:

public static class Number
{


    private static object GetConstValue(System.Type t, string propertyName)
    {
        System.Reflection.FieldInfo pi = t.GetField(propertyName, System.Reflection.BindingFlags.Static
            | System.Reflection.BindingFlags.Public
            | System.Reflection.BindingFlags.NonPublic
            );

        return pi.GetValue(null);
    } // End Function GetConstValue 


    private static object GetMinValue(System.Type t)
    {
        return GetConstValue(t, "MinValue");
    } // End Function GetMinValue 


    private static object GetMaxValue(System.Type t)
    {
        return GetConstValue(t, "MaxValue");
    } // End Function GetMaxValue 



    private static object UnsignedToSigned(object value, System.Type t)
    {
        if (object.ReferenceEquals(t, typeof(System.UInt64)))
            return UnsignedToSigned((System.UInt64)value);
        else if (object.ReferenceEquals(t, typeof(System.UInt32)))
            return UnsignedToSigned((System.UInt32)value);
        else if (object.ReferenceEquals(t, typeof(System.UInt16)))
            return UnsignedToSigned((System.UInt16)value);
        else if (object.ReferenceEquals(t, typeof(System.Byte)))
            return UnsignedToSigned((System.Byte)value);

        throw new System.NotImplementedException($"UnsignedToSigned for type {t.Name} is not implemented.");
    }


    public static object UnsignedToSigned(object value)
    {
        if (value == null)
            throw new System.ArgumentNullException(nameof(value), "Parameter cannot be NULL.");

        System.Type t = value.GetType();

        return UnsignedToSigned(value, t);
    }


    public static T UnsignedToSigned<T>(object value)
        where T:System.IComparable 
    {
        if (value == null)
            throw new System.ArgumentNullException(nameof(value), "Parameter cannot be NULL.");

        System.Type t = value.GetType();
        System.Type tRet = typeof(T);

        int sizeRet = System.Runtime.InteropServices.Marshal.SizeOf(tRet);
        int sizeValue = System.Runtime.InteropServices.Marshal.SizeOf(t);

        if (sizeRet != sizeValue)
        {
            throw new System.NotSupportedException($"Type mismatch: {tRet.Name} is not the matching signed type for {t.Name}");
        }

        System.IComparable minValue = (System.IComparable)GetMinValue(t);

        System.IComparable minValueRet = (System.IComparable)GetMinValue(tRet);
        if (minValueRet.CompareTo(System.Convert.ChangeType(0, tRet)) == 0)
        {
            throw new System.NotSupportedException($"Type mismatch: {tRet.Name} is not a signed type.");
        }

        // If we already have an signed type
        // Type mismatch already prevented 
        if (minValue.CompareTo(System.Convert.ChangeType(0, t)) != 0)
        {
            return (T)value;
        }

        return (T)UnsignedToSigned(value, t);
    }

    private static object SignedToUnsigned(object value, System.Type t)
    {
        if (object.ReferenceEquals(t, typeof(System.Int64)))
            return SignedToUnsigned((System.Int64)value);
        else if (object.ReferenceEquals(t, typeof(System.Int32)))
            return SignedToUnsigned((System.Int32)value);
        else if (object.ReferenceEquals(t, typeof(System.Int16)))
            return SignedToUnsigned((System.Int16)value);
        else if (object.ReferenceEquals(t, typeof(System.SByte)))
            return SignedToUnsigned((System.SByte)value);

        throw new System.NotImplementedException("SignedToUnsigned for type " + t.FullName + " is not implemented.");
    }


    public static object SignedToUnsigned(object value)
    {
        if (value == null)
            throw new System.ArgumentNullException(nameof(value), "Parameter cannot be NULL.");

        System.Type t = value.GetType();
        return SignedToUnsigned(value, t);
    }


    public static T SignedToUnsigned<T>(object value)
        where T : System.IComparable
    {
        if (value == null)
            throw new System.ArgumentNullException(nameof(value), "Parameter cannot be NULL.");

        System.Type t = value.GetType();
        System.Type tRet = typeof(T);

        int sizeRet = System.Runtime.InteropServices.Marshal.SizeOf(tRet);
        int sizeValue = System.Runtime.InteropServices.Marshal.SizeOf(t);

        if (sizeRet != sizeValue)
        {
            throw new System.NotSupportedException($"Type mismatch: {tRet.Name} is not the matching unsigned type for {t.Name}");
        }

        System.IComparable minValue = (System.IComparable)GetMinValue(t);

        System.IComparable minValueRet = (System.IComparable)GetMinValue(tRet);
        if (minValueRet.CompareTo(System.Convert.ChangeType(0, tRet)) != 0)
        {
            throw new System.NotSupportedException($"Type mismatch: {tRet.Name} is not an unsigned type.");
        }

        // If we already have an unsigned type
        // Type mismatch already prevented 
        if (minValue.CompareTo(System.Convert.ChangeType(0, t)) == 0)
        {
            return (T)value;
        }

        return (T)SignedToUnsigned(value, t);
    }

    private static System.Int64 UnsignedToSigned(System.UInt64 uintValue)
    {
        return unchecked((System.Int64)uintValue + System.Int64.MinValue);
    }


    private static System.UInt64 SignedToUnsigned(System.Int64 intValue)
    {
        return unchecked((System.UInt64)(intValue - System.Int64.MinValue));
    }


    private static System.Int32 UnsignedToSigned(System.UInt32 uintValue)
    {
        return unchecked((System.Int32)uintValue + System.Int32.MinValue);
    }


    private static System.UInt32 SignedToUnsigned(System.Int32 intValue)
    {
        return unchecked((System.UInt32)(intValue - System.Int32.MinValue));
    }



    private static System.Int16 UnsignedToSigned(System.UInt16 uintValue)
    {
        return (System.Int16) unchecked((System.Int16)uintValue + System.Int16.MinValue);
    }


    private static System.UInt16 SignedToUnsigned(System.Int16 intValue)
    {
        return unchecked((System.UInt16)(intValue - System.Int16.MinValue));
    }



    private static sbyte UnsignedToSigned(byte ulongValue)
    {
        return (sbyte) unchecked((sbyte)ulongValue + sbyte.MinValue);
    }


    private static byte SignedToUnsigned(sbyte longValue)
    {
        return unchecked((byte)(longValue - sbyte.MinValue));
    }

}