简体   繁体   English

如何从无符号类型的通用参数中得出带符号的类型,反之亦然?

[英]How to derive signed type from unsigned type generic parameter, and vice-versa?

I want to make generic metods ToSigned, ToUnsinged. 我想将通用方法设为ToSigned,ToUnsinged。
This is what i have 这就是我所拥有的

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


}

I have successfully implemented SignedToUnsigned and UnsignedToSigned, but how do I derive the signed type from an unsigned type, or the unsigned type from a signed type ? 我已经成功实现了SignedToUnsigned和UnsignedToSigned,但是如何从无符号类型派生有符号类型,或者从有符号类型派生无符号类型呢?

There's no inbuilt mechanism for this; 没有内置的机制。 you'd have to hard-code it based on the T : 您必须根据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

now repeat for all expected types. 现在对所有期望的类型重复。

Note that this isn't as expensive as it'll look, as the JIT happens per- T for value-type T , and the JIT can remove branches based on constants including typeof(T) . 请注意,这不是因为它会看起来昂贵,因为JIT发生per- T的价值型T ,而JIT可以去除基于常量,包括分支机构typeof(T)

I wonder, though, whether a better option is extension methods on specific T : 不过,我不知道是否更好的选择是对特定 T扩展方法:

public static Number<uint> ToUnsigned(this Number<int> val)
      => new Number<uint>((uint)val.Value); // etc

There's no way to do this built-in. 没有内置的方法。
Also, note that Equals checks if it's the same object, not the same value, so the result for your (IsSigned, IsUnsigned) is wrong. 另外,请注意,Equals会检查它是否是相同的对象,而不是相同的值,因此您的(IsSigned,IsUnsigned)的结果是错误的。

You could manually map the types with dictionaries (or use if statements, since there are only 4 integer types), and then call your method with reflection: 您可以使用字典手动映射类型(或使用if语句,因为只有4个整数类型),然后使用反射调用方法:

But if you use ifs and casts instead, and make due without reflection, it will be significantly faster. 但是,如果您使用ifs和casts代替,并且在没有反射的情况下进行到期,那么它将明显更快。

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 });
    }


}

Why don't you just use object instead of generics, eg: 为什么不使用对象而不是泛型,例如:

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));
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 将通用类型转换为其基本类型,反之亦然 - Converting generic type to its base and vice-versa c# - 可以从C#类型转换为System.Type但反之亦然 - c# - can convert from C# type to System.Type but not vice-versa 从无符号获取有符号的值的方法,反之亦然 - Way to get signed value from unsigned and vice versa 如何使用BluetoothDeviceInfo中的信息识别HID设备,反之亦然 - How to identify HID Device with information from BluetoothDeviceInfo or vice-versa 在 C# 4.0 中,是否可以从泛型类型参数派生 class? - In C# 4.0, is it possible to derive a class from a generic type parameter? 如何将IncomingWebRequestContext转换为HttpRequestMessage类型,反之亦然 - How to cast a IncomingWebRequestContext to HttpRequestMessage type and vice versa 在C#中将数字数组通用转换为字节,反之亦然 - Generic conversion of number arrays into bytes and vice-versa in C# 从参数类型派生方法返回类型 - Derive method return type from parameter type 如何将数据从C#推送到ZeroMQ并从Node.JS提取,反之亦然? - How to Push data from C# to ZeroMQ and Pull from Node.JS or vice-versa? 如何将 Windows 任务栏从“显示”切换到“自动隐藏”(反之亦然)? - How to toggle/switch Windows taskbar from “show” to “auto-hide” (and vice-versa)?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM