2010-04-06 2 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' из словаря, не указывая его? –

+0

Да, это то, чего я хочу. – DNNX

ответ

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.

+0

Вы правы, это не то, что я хочу. Как я уже сказал, я хочу использовать этот метод для разных типов словарей со строковыми ключами, т. Е.не только на IDictonary , но и на IDictonary , IDictonary > и т. д. – DNNX

+0

C# - это не совсем правильный язык для этого, проверка статического типа - это король. Ищите динамический язык, такой как Python или Ruby. Или язык, который реализует дженерики через стирание типа, например Java. –

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, что Т вы должны иметь что-то типа Т в параметрах.

Редактировать

Может быть, лучше всего было бы

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 x = dict.GetValueAs("A", new Dictionary<string,int>).GetValueAs("B", default(int)); 
+0

Спасибо за совет, человек. Я рассмотрел такой подход. Это не очень изящно. «Цепные вызовы» невозможны, например (dict.GetValueAs > («A»). GetValueAs («B»)), использование ключевого слова var невозможно (var x = dict.GetValueAs («C»)), невозможно вернуть значение из словаря напрямую (return dict.GetValueAs («C»);) и т. д. – DNNX

+0

Другие варианты - это вернуть значение, но также передать значение, чтобы получить тип, чтобы что-то вроде var x = dict.GetValueAs («A», новый словарь ()). GetValueAs («B», default (int)); Также уродливый, но единственный другой способ, о котором я могу думать. – juharr

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, потому что я ссылаюсь на внешний код, который возвращает словари. – DNNX

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 вам не нужно указывать типы ключа и значения, однако, поскольку словарь наследует от этого, функция остается, независимо от того, как создается ваш словарь. Вы даже можете просто использовать объект вместо строки для ключа.

Смежные вопросы