2010-04-06 109 views
4

我有类似下面的扩展方法:如何指定泛型方法类型参数部分

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"); 

+1

因此,基本上你想要做的是从'字典'推断'R'的类型,而不是指定它? – 2010-04-06 12:37:23

+0

是的,这就是我想要的。 – DNNX 2010-04-06 13:14:14

回答

1

只要您只使用它的对象字典,你可以约束吨至是引用类型,使投有效:

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要么。

+0

你是对的,那不是我想要的。正如我所说的,我想在不同类型的字符串键词典上使用这种方法,即不仅在IDictonary <字符串,对象>上,而且在IDictonary ,IDictonary <字符串,IEnumerable >等。 – DNNX 2010-04-06 13:42:19

+0

C#不是正确的语言,静态类型检查是King。寻找像Python或Ruby这样的动态语言。或者是一种通过类型擦除实现泛型的语言,如Java。 – 2010-04-06 13:48:59

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); 

基本上有它infere是你有什么吨至具有类型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和链,这让你能够控制的默认值是什么的能力。

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

谢谢你的建议,男人。我已经考虑过这种方法。我觉得这不是很优雅。 “连锁调用”是不可能的,例如(dict.GetValueAs >(“A”)。GetValueAs (“B”)),使用var关键字是不可能的(var x = dict.GetValueAs (“C”)) ),不可能直接从字典返回值(返回dict.GetValueAs (“C”);)等 – DNNX 2010-04-06 15:55:59

+0

另一种选择是返回值,但也传递一个值只是为了获得类型如var x = dict.GetValueAs(“A”,新词典())。GetValueAs(“B”,default(int));也丑陋,但我能想到的唯一的其他方式。 – juharr 2010-04-08 23:19:12

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 

可能不希望这样做无论是干草的嗡嗡声。

+0

好的解决方案。但是,我想使用内置的.NET IDictionary的扩展方法,因为我指的是返回IDictionaries的外部代码。 – DNNX 2010-04-06 15:59:08

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的,你不需要为键和值指定类型,然而,随着字典继承此功能,无论您的字典是如何创建的。你甚至可以使用对象而不是字符串作为键。

相关问题