如何部分指定泛型方法类型参数

时间:2010-04-06 12:24:38

标签: c# generics .net-4.0 extension-methods covariance

我有一个如下所示的扩展方法:

public static T GetValueAs<T, R>(this IDictionary<string, R> dictionary, string fieldName)
    where T : R
{
    R value;
    if (!dictionary.TryGetValue(fieldName, out value))
        return default(T);

    return (T)value;
}

目前,我可以通过以下方式使用它:

    var dictionary = new Dictionary<string, object>();
    //...
    var list = dictionary.GetValueAs<List<int>, object>("A"); // this may throw ClassCastException - this is expected behavior;

它工作得很好,但第二个类型参数真的很烦人。是否有可能在C#4.0中重写GetValueAs是这样一种方式,该方法仍然适用于不同类型的字符串键控字典,并且不需要在调用代码中指定第二个类型参数,即使用

    var list = dictionary.GetValueAs<List<int>>("A");
或至少类似
    var list = dictionary.GetValueAs<List<int>, ?>("A");
而不是
    var list = dictionary.GetValueAs<List<int>, object>("A");

4 个答案:

答案 0 :(得分:1)

只要您只在对象的词典中使用它,就可以将T约束为引用类型以使转换有效:

public static T GetValueAs<T>(this IDictionary<string, object> dictionary, string fieldName)
  where T : class {
  object value;
  if (!dictionary.TryGetValue(fieldName, out value))
    return default(T);

  return (T)value;
}

但那可能不是你想要的。请注意C#版本4 doesn't solve your problem

答案 1 :(得分:0)

怎么样?
public static void GetValueAs<T, R>(this IDictionary<string, R> dictionary, string fieldName, out T value)
    where T : R
{
    value = default(T);
    dictionary.TryGetValue(fieldName, out value)
}

然后你可以做类似

的事情
List<int> list;
dictionary.GetValueAs("fieldName", out list);

基本上要知道你需要在参数中使用T类型的东西。

修改

也许更好的方法是

public static T GetValueAs<T, R>(
    this IDictionary<string, R> dictionary, 
    string fieldName, 
    T defaultValue)
    where T : R
{
    R value = default(R);
    return dictionary.TryGetValue(fieldName, out value) ? 
        (T)value : defaultValue;
}

然后你可以使用var和chain,这使你能够控制默认值。

var x = dict.GetValueAs("A", new Dictionary<string,int>).GetValueAs("B", default(int));

答案 2 :(得分:0)

也许你可以为这种行为制作自己的字典类:

    public class CastableDictionary<TKey, TValue> : Dictionary<TKey, TValue>
        {
            public TOut GetValueAs<TOut>(TKey key) where TOut : TValue
            {
                TValue result;
                if (this.TryGetValue(key, out result))
                {
                    return (TOut)result;
                }
                return default(TOut);
            }
        }



var d = new CastableDictionary<string, object>();

        d.Add("A", 1);

        d.Add("B", new List<int>() { 1, 2, 3});

        var a = d.GetValueAs<int>("A"); // = 1

        var b = d.GetValueAs<List<int>>("B"); //= 1, 2, 3 

可能不想干草哼。

答案 3 :(得分:0)

我错过了什么,当然这就是你想要的吗?也许你需要更好的转换,但对于一般演员,这应该做:

public static T getValueAs<T>(this IDictionary dict, string key)
{            
    try
    {
        return (T)dict[key];
    } catch
    {
        return default(T);
    }            
}

用法只是

MyDictionary.getValueAs<Int32>("hello");

使用IDictionary,您不需要指定键和值的类型,但是当字典继承此函数时,无论您的字典是如何创建的,函数都会保留。您甚至可以使用对象而不是字符串作为密钥。