Как указать общие параметры типа метода частично - PullRequest
5 голосов
/ 06 апреля 2010

У меня есть метод расширения, как показано ниже:

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 ]

1 голос
/ 06 апреля 2010

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

0 голосов
/ 09 мая 2017

Я что-то упустил, конечно, это все, что вы хотите? Возможно, вам нужно лучшее преобразование, но для общего приведения это должно сделать:

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

использование просто быть

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

С IDictionary вам не нужно указывать типы для ключа и значения, однако, поскольку словарь наследует от этого, функция остается, независимо от того, как создается ваш словарь. Вы даже можете использовать объект вместо строки для ключа.

0 голосов
/ 06 апреля 2010

Может быть, вы могли бы сделать свой собственный класс словаря для этого поведения:

    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 голосов
/ 06 апреля 2010

А как же

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, нужно иметь что-то типа 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));
...