简体   繁体   English

避免在泛型方法中进行过多的类型检查?

[英]Avoid excessive type-checking in generic methods?

My question concerns type-checking in a chain of generic methods. 我的问题涉及一系列通用方法中的类型检查。 Let's say I have an extension method that attempts to convert a byte array to an int, decimal, string, or DateTime. 假设我有一个扩展方法,它尝试将字节数组转换为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));
}

This calls a method called FromString that translates the concatenated string to a specific type. 这会调用一个名为FromString的方法,该方法将连接的字符串转换为特定的类型。 Unfortunately, the business logic is completely dependent on the type T. So I end up with a megalithic if-else block: 不幸的是,业务逻辑完全依赖于类型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 ...
 }

At this point, I would prefer multiple methods with the same name and different return types, something along the lines of this: 在这一点上,我更喜欢具有相同名称和不同返回类型的多个方法,类似于以下内容:

// <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>

... but I realize this is not valid, as T can't be constrained to a specific type, and without it, all of the methods will have the same conflicting signature. ...但我意识到这是无效的,因为T不能被约束到特定类型,没有它,所有方法都将具有相同的冲突签名。

Is there a feasible way to implement FromString without the excessive type-checking? 有没有一种可行的方法来实现FromString而没有过多的类型检查? Or might there be a better way to approach this problem altogether? 或者可能有更好的方法来解决这个问题?

Or might there be a better way to approach this problem altogether? 或者可能有更好的方法来解决这个问题?

Sure, there is one: you can make each converter into a lambda, make a dictionary of them, and use them for the conversion, like this: 当然,有一个:你可以将每个转换器变成一个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);
}

In general, if you have to write logic that must always check the type of a generic type parameter, you are not actually writing code that benefits from being generic. 通常,如果必须编写必须始终检查泛型类型参数类型的逻辑,那么实际上并不是编写受益于泛型的代码。 That being the case, and assuming the actual problem you're trying to solve is the need to convert a byte array into some predictable built-in type that it represents, I recommend you abandon this approach and use the methods in the BitConverter class . 既然如此,假设您要解决的实际问题是需要将字节数组转换为它所代表的某种可预测的内置类型,我建议您放弃这种方法并使用BitConverter类中的方法。

At the point where you could determine the value of T, simply call the appropriate method on the BitConverter class. 在您可以确定T的值的位置,只需在BitConverter类上调用适当的方法即可。

Update: If a generic solution is necessary, I'd suggest something similar to dasblinkenlight 's answer, though I would let the caller inject the converter (after all, the caller knows the requisite result type), which avoids the problem of maintaining a list of conversion functions alongside the generic method: 更新:如果需要通用解决方案,我建议类似于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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM