7

我的问题涉及一系列通用方法中的类型检查。假设我有一个扩展方法,它尝试将字节数组转换为 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 而无需过多的类型检查?或者是否有更好的方法来完全解决这个问题?

4

2 回答 2

10

或者是否有更好的方法来完全解决这个问题?

当然,有一个:您可以将每个转换器变成一个 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);
}
于 2013-08-09T20:26:16.323 回答
6

通常,如果您必须编写必须始终检查泛型类型参数类型的逻辑,那么您实际上并没有编写从泛型中受益的代码。既然如此,并且假设您要解决的实际问题是需要将字节数组转换为它所代表的某种可预测的内置类型,我建议您放弃这种方法并使用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);
}
于 2013-08-09T20:25:54.637 回答