为什么以下代码无法编译? 如何创建一个调用适当的" BitConverter.GetBytes"如果泛型类型是" int"," bool"," char"等等,则超载? 更一般地说,如何创建一个基于泛型参数类型调用非泛型方法的泛型方法?
using System;
public class Test
{
public static void Main()
{
var f = new Foo();
f.GetBytes(10); // should call BitConverter.GetBytes(int);
f.GetBytes(true); // should call BitConverter.GetBytes(bool);
f.GetBytes('A'); // should call BitConverter.GetBytes(char);
}
}
public class Foo
{
public byte[] GetBytes <TSource> (TSource input)
{
BitConverter.GetBytes(input);
}
}
答案 0 :(得分:8)
更一般地说,如何创建一个基于泛型参数类型调用非泛型方法的泛型方法?
一般情况下,您不能,除非相关方法将System.Object
作为参数。问题是泛型不仅限于方法调用参数允许的类型。
您最接近的是使用运行时绑定:
public byte[] GetBytes <TSource> (TSource input)
{
dynamic obj = input;
BitConverter.GetBytes(obj);
}
这会将方法绑定逻辑推送到运行时,如果没有合适的方法可以调用,则会抛出。
答案 1 :(得分:1)
这不起作用的原因是泛型方法仍然静态地解析对其中的方法的调用。由于TSource
可以是任何类型,因此它只能调用BitConverter
上带有object
参数的方法。由于不存在,编译失败。
获得所需行为的唯一方法是使用dynamic
:
public byte[] GetBytes <TSource> (TSource input)
{
BitConverter.GetBytes((dynamic)input);
}
虽然泛型参数现在是多余的,但您没有类型安全性。
在这种情况下,您可以创建许多匹配的重载,例如
public byte[] GetBytes(bool b) { ... }
public byte[] GetBytes(int i) { ... }
或者使用Func<T, byte[]>
参数并包装您需要的每个BitConverter
方法,例如
public void DoSomething<T>(T input, Func<T, byte[]> f)
{
byte[] bytes = f(input);
//handle bytes
}
DoSomething(true, BitConverter.GetBytes);
可能会给你更大的灵活性。
答案 2 :(得分:1)
在代码调用BitConverter.GetBytes
的情况下,类型为TSource
,因此调用无法通过编译器进行静态绑定。您可以使用动态调用解决此问题,这意味着它可以正常编译,然后在运行时解析:
…
public byte[] GetBytes(dynamic input)
{
return BitConverter.GetBytes(input);
}
您将为使用动态调用支付性能损失,如果没有合适的调用方法,您将获得运行时异常。
答案 3 :(得分:1)
鉴于BitConverter.GetBytes
只有“仅”10次重载,所以明确反映它们并非不可能:
public class Foo
{
public byte[] GetBytes(bool input) { return BitConverter.GetBytes(input); }
public byte[] GetBytes(char input) { return BitConverter.GetBytes(input); }
public byte[] GetBytes(double input) { return BitConverter.GetBytes(input); }
public byte[] GetBytes(float input) { return BitConverter.GetBytes(input); }
public byte[] GetBytes(int input) { return BitConverter.GetBytes(input); }
public byte[] GetBytes(short input) { return BitConverter.GetBytes(input); }
public byte[] GetBytes(long input) { return BitConverter.GetBytes(input); }
public byte[] GetBytes(uint input) { return BitConverter.GetBytes(input); }
public byte[] GetBytes(ulong input) { return BitConverter.GetBytes(input); }
public byte[] GetBytes(ushort input) { return BitConverter.GetBytes(input); }
}
它不是通用的(你曾经要求的),并且不能扩展到更复杂的例子,但如果数字很小,那么它就是 方法。
答案 4 :(得分:1)
如果您愿意受到性能影响,可以使用反射和对象GetBytes的扩展。例如....
public static class Extensions
{
#region Fields
public static Type bcType;
#endregion
#region Constructor
static Extensions()
{
bcType = typeof(BitConverter);
}
#endregion
public static byte[] GetBytes(this object value)
{
Type typeObj = value.GetType();
MethodInfo miGetBytes = bcType.GetMethod("GetBytes", new Type[] { typeObj });
if (miGetBytes == null)
throw new InvalidOperationException("Method: GetBytes on BitConverter does not have an overload accepting one paramter of type: " + typeObj.FullName);
byte[] bytesRet = (byte[])miGetBytes.Invoke(null, new object[] { obj });
return bytesRet;
}
}
所以GetBytes接受一个对象。然后它得到它的类型并尝试根据传入的对象类型从BitConverter获取MethodInfo。如果它找不到接受该类型作为参数的重载,它会抛出一个InvalidOperation异常。如果是,则调用它将obj实例作为值传递并返回字节数组。
E.g。使用代码,
//make sure the extensions namespace is defined where this code is run.
Console.WriteLine(((ushort)255).GetBytes().ToBase64());
Console.WriteLine(10.0.GetBytes().ToBase64());
Console.WriteLine(((int)2000000000).GetBytes().ToBase64());
Console.WriteLine(((short)128).GetBytes().ToBase64());
//Below causes an error
Console.WriteLine("cool".GetBytes().ToBase64()); //because BitConvert.GetBytes has no overload accepting an argument of type string.
答案 5 :(得分:0)
你需要使用反射来做到这一点。
GetBytes
静态类型获取BitConverter
方法组。TSource
。Invoke
方法调用该特定方法。如果您对某些内容不熟悉,我可以使用这些步骤的代码扩展答案。
编辑:或者像其他人一样使用dynamic
建议并为自己保留一些工作。
答案 6 :(得分:0)
您的代码无法编译,因为编译器无法验证TSource
是否接受BitConverter.GetBytes()
的任何类型。您可以单独检查每种类型并投射:
public byte[] GetBytes <TSource> (TSource input)
{
var t = typeof(TSource);
return (t == typeof(int)) ? BitConverter.GetBytes((int) (object) input)
: (t == typeof(bool)) ? BitConverter.GetBytes((bool)(object) input)
: (t == typeof(char)) ? BitConverter.GetBytes((char)(object) input)
: null;
}