我正在解析二进制文件。因此,我写了类似下面的东西。
public T Parse<T>(BinaryReader reader)
{
if (typeof(T) == typeof(byte))
return reader.ReadByte();
else if (typeof(T) == typeof(int))
return reader.ReadInt32();
// ...
}
然而,这并没有被编译。
不能隐式地将'...'类型转换为'T'
这样做对我来说会非常方便。
如何从一个通用方法中返回任何基元?
这在检查运行时类型的通用代码中相当常见。这是因为编译器并不 "知道 "字节可以直接转换为T,即使因为类型检查,它和T是一样的。
public T Parse<T>(BinaryReader reader)
{
if (typeof(T) == typeof(byte))
return (T)(object)reader.ReadByte();
else if (typeof(T) == typeof(int))
return (T)(object)reader.ReadInt32();
// all returns will need similar casts
}
这样做的缺点是,投向对象会导致一个框选操作,增加GC的压力,所以对于性能敏感的代码来说可能是不好的。
我不知道你为什么需要这个功能(考虑到你失去了编译时的安全性,是否值得这么麻烦),但你可以尝试通过以下方法去除解决方案中不必要的分配。@Mike Zboray:
public static T Parse<T>(BinaryReader reader)
{
return ReaderProvider<T>.ReaderFunc(reader);
}
class ReaderProvider<T>
{
public static readonly Func<BinaryReader, T> ReaderFunc;
static ReaderProvider()
{
MethodInfo mi ;
if(typeof(T) == typeof(byte))
{
mi = typeof(BinaryReader).GetMethod(nameof(BinaryReader.ReadByte));
}
else if(typeof(T) == typeof(int))
{
mi = typeof(BinaryReader).GetMethod(nameof(BinaryReader.ReadInt32));
}
// ....
else
{
throw new ArgumentOutOfRangeException($"{typeof(T).FullName}");
}
var p = Expression.Parameter(typeof(BinaryReader));
ReaderFunc = Expression.Lambda<Func<BinaryReader, T>>(Expression.Call(p, mi), p).Compile();
}
}
例子用法。
var ms = new MemoryStream();
ms.Write(new byte[] { 1, 2, 0, 0, 0 }, 0, 5);
ms.Seek(0, SeekOrigin.Begin);
var x = new BinaryReader(ms);
Console.WriteLine(Parse<byte>(x));
Console.WriteLine(Parse<int>(x));
我还强烈建议坚持 BinaryReader.ReadX
方法。如果这不适合,那么就对两种实现的基准性能进行测试。