[英]Avoid excessive type-checking in generic methods?
我的问题涉及一系列通用方法中的类型检查。 假设我有一个扩展方法,它尝试将字节数组转换为int,decimal,string或DateTime。
public static T Read<T>(this ByteContainer ba, int size, string format) where T : struct, IConvertible
{
var s = string.Concat(ba.Bytes.Select(b => b.ToString(format)).ToArray());
var magic = FromString<T>(s);
return (T)Convert.ChangeType(magic, typeof(T));
}
这会调用一个名为FromString的方法,该方法将连接的字符串转换为特定的类型。 不幸的是,业务逻辑完全依赖于类型T.所以我最终得到了一个巨石if-else块:
private static T FromString<T>(string s) where T : struct
{
if (typeof(T).Equals(typeof(decimal)))
{
var x = (decimal)System.Convert.ToInt32(s) / 100;
return (T)Convert.ChangeType(x, typeof(T));
}
if (typeof(T).Equals(typeof(int)))
{
var x = System.Convert.ToInt32(s);
return (T)Convert.ChangeType(x, typeof(T));
}
if (typeof(T).Equals(typeof(DateTime)))
... etc ...
}
在这一点上,我更喜欢具有相同名称和不同返回类型的多个方法,类似于以下内容:
// <WishfulThinking>
private static decimal FromString<T>(string s)
{
return (decimal)System.Convert.ToInt32(s) / 100;
}
private static int FromString<T>(string s)
{
return System.Convert.ToInt32(s);
}
// </WishfulThinking>
...但我意识到这是无效的,因为T不能被约束到特定类型,没有它,所有方法都将具有相同的冲突签名。
有没有一种可行的方法来实现FromString而没有过多的类型检查? 或者可能有更好的方法来解决这个问题?
或者可能有更好的方法来解决这个问题?
当然,有一个:你可以将每个转换器变成一个lambda,制作它们的字典,并将它们用于转换,如下所示:
private static IDictionary<Type,Func<string,object>> Converters = new Dictionary<Type,Func<string,object>> {
{typeof(int), s => Convert.ChangeType(System.Convert.ToInt32(s), typeof(int))}
, {typeof(decimal), s => Convert.ChangeType((decimal)System.Convert.ToInt32(s) / 100, typeof(decimal))}
, ... // And so on
};
public static T Read<T>(this ByteContainer ba, int size, string format) where T : struct, IConvertible {
Func<string,object> converter;
if (!Converters.TryGetValue(typeof(T), out converter)) {
throw new ArgumentException("Unsupported type: "+typeof(T));
}
var s = string.Concat(ba.Bytes.Select(b => b.ToString(format)).ToArray());
return (T)converter(s);
}
通常,如果必须编写必须始终检查泛型类型参数类型的逻辑,那么实际上并不是编写受益于泛型的代码。 既然如此,假设您要解决的实际问题是需要将字节数组转换为它所代表的某种可预测的内置类型,我建议您放弃这种方法并使用BitConverter类中的方法。
在您可以确定T的值的位置,只需在BitConverter类上调用适当的方法即可。
更新:如果需要通用解决方案,我建议类似于dasblinkenlight的答案,虽然我会让调用者注入转换器(毕竟,调用者知道必需的结果类型),这避免了维护转换函数列表以及泛型方法:
public static T Read<T>(this ByteContainer ba, int size, string format,
Func<string, T> converter) where T : struct, IConvertible
{
var s = string.Concat(ba.Bytes.Select(b => b.ToString(format)).ToArray());
return converter(s);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.