Получение правильного вывода типа для более сложного типа в универсальном методе - PullRequest
1 голос
/ 26 октября 2010

Я работаю в среде .NET 2.0. У меня работает некоторый код, просто хочу, чтобы он работал немного более элегантно.

Мне нужно эффективно «отразить» объект Dictionary, чтобы, если мы начнем с такого объекта, как этот

Dictionary<TKey,TValue> StartDictionary;

Мы можем отразить это так

Dictionary<TValue,TKey> MirroredDictionary = MirrorDictionary(StartDictionary);

И мы получим новый словарь с заменой значений и ключей для каждой KeyValuePair

Прежде чем кто-нибудь спросит меня, почему: исходный словарь достаточно велик и загружается один раз из вызовов отражений при загрузке моей программы. Я не хочу запускать одни и те же вызовы отражения во второй раз, чтобы загрузить зеркальный словарь. Создание зеркального словаря и заполнение его значений и ключей так, как я придумал, показалось мне гораздо менее затратным.

Таким образом, будучи человеком, который ненавидит переписывать вещи, я решил написать универсальный метод в классе помощника, я должен сделать Зеркало, используя Дженерики.

Теперь учтите, что я уже писал простые универсальные методы для нормальных скалярных типов

Вот что я придумал

 public static TOutDic MirrorDictionary<TInDic, TOutDic>(TInDic InDictionary)
  where TInDic : IDictionary
  where TOutDic : IDictionary
{
  Type[] KVPTypes = typeof(TInDic).GetGenericArguments();
  Type TKey = KVPTypes[0];
  Type TValue = KVPTypes[1];
  Type TDic = typeof(Dictionary<,>).MakeGenericType(TValue, TKey);
  IDictionary OutDic = (IDictionary)Activator.CreateInstance(TDic);
  foreach (DictionaryEntry DE in (IDictionary)InDictionary) OutDic.Add(DE.Value, DE.Key);
  return (TOutDic)OutDic;
}

Немного там, но это работает, загружает типы ключей и значений и создает экземпляр зеркального словаря

Затем, просто просматривая базовые DictionaryEntries в InDictionary, он добавляет элементы в OutDic и возвращает его приведения к ожидаемому типу

Компилируется просто отлично

Теперь, когда я вызываю его, я думаю, точно так же, как когда я вызываю универсальный метод для скалярного типа, я мог бы просто использовать наши фрагменты кода выше, скажем

Dictionary<TValue,TKey> MirroredDictionary = MirrorDictionary(StartDictionary);

Но это не компилирует дает мне

Аргументы типа для метода MirrorDictionary (TInDic) 'не могут быть выведены из использования. Попробуйте указать аргументы типа явно.

Так что, если я вместо этого назову это

      Dictionary<TValue, TKey> MirrorDic = MirrorDictionary<Dictionary<Tkey, TValue>, Dictionary<TValue,TKey>>(StringDic);

Он компилируется и работает как шарм.

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

Ответы [ 4 ]

1 голос
/ 26 октября 2010

Вы можете значительно упростить жизнь компилятору, сообщив ему тип ключа и значения следующим образом:

public static Dictionary<TValue, TKey> MirrorDictionary<TKey, TValue>
    (Dictionary<TKey, TValue> source)
{
    Dictionary<TValue, TKey> destination = new Dictionary<TValue, TKey>();

    foreach (KeyValuePair<TKey, TValue> kvp in source)
    {
        destination.Add(kvp.Value, kvp.Key);
    }

    return destination;
}

Я не думаю, что вам вообще нужно здесь размышлять.

Примериспользование:

static void Main(string[] args)
{
    Dictionary<int, string> source = new Dictionary<int, string>();
    source.Add(3, "foo");
    source.Add(4, "bar");

    DumpDic(source);

    DumpDic(MirrorDictionary(source));

    Console.ReadLine();

}

, где DumpDic:

public static void DumpDic<TK, TV>(Dictionary<TK, TV> dic)
{
    foreach (KeyValuePair<TK, TV> keyValuePair in dic)
    {
        Console.WriteLine("{0} => {1}", keyValuePair.Key, keyValuePair.Value);
    }
}
1 голос
/ 26 октября 2010

Вот решение 3.5 (вы также можете использовать его в 2.0 с VS2008 и LinqBridge)

IDictionary<TValue, TKey> MirrorDictionary<TKey, TValue>(IDictionary<TKey, TValue> dict)
{
    return dict.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
}

И чистый раствор 2.0

IDictionary<TValue, TKey> MirrorDictionary<TKey, TValue>(IDictionary<TKey, TValue> dict)
{
    Dictionary<TValue, TKey> newDict = new Dictionary<TValue, TKey>();
    foreach(KeyValuePair<TKey, TValue> kvp in dict)
    {
        newDict.Add(kvp.Value, kvp.Key);
    }
    return newDict;
}

Вывод типа должен хорошо работать с обоими решениями (так как они имеют одинаковую подпись)

0 голосов
/ 26 октября 2010

Вы должны сказать ему, что такое TValue и TKey. Если они не определены в сигнатуре метода, вызывающего этот код, они не имеют каких-либо конкретных типов. Вам нужно дать что-то вроде:

Dictionary<string, int> MirroredDictionary = MirrorDictionary(StartDictionary);
0 голосов
/ 26 октября 2010

Вы можете определить словарь Out как параметр out. Вывод типа не смотрит тип переменной, которую вы назначаете, а только типы параметров. Вот почему это не компилируется.

...