[英]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.