Метод расширения, чтобы получить список словарей в виде набора данных? - PullRequest
0 голосов
/ 15 ноября 2010

Я пытаюсь преобразовать объекты списка словаря в набор данных.Список поступает из анализатора JSON.Я решил использовать это как возможность узнать о методах расширения.

Метод расширения для отдельного словаря работает, но метод для Списка словарей мне не подходит, главным образом потомувызов становится

DataSet myExampleDataSet = myExampleDictionary.ToDataSet<Dictionary<string,string>,string,string>();

Я что-то упустил?Неужели все должно быть так сложно?Должен ли я просто бросить метод Dictionary .ToDataSet в foreach?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Collections;

//fixed code below
namespace TT.Utils
{
    public static class DictionaryExtensions
    {
        /// <summary>
        /// Dictionary to DataSet
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="currentDictionary"></param>
        /// <returns></returns>
        public static DataSet ToDataSet<TKey, TValue>(this IDictionary<TKey, TValue> currentDictionary)
        {
            DataSet exportedDataSet = new DataSet();
            DataTable exportedDataTable = exportedDataSet.Tables.Add();
            foreach (TKey key in currentDictionary.Keys)
            {
                exportedDataTable.Columns.Add(key.ToString());
            }
            DataRow newRow = exportedDataTable.NewRow();
            foreach (KeyValuePair<TKey, TValue> entry in currentDictionary)
            {
                string key = entry.Key.ToString();

                string val = string.Empty;
                if (entry.Value != null)
                {
                    val = entry.Value.ToString();
                }

                newRow[key] = val;

            }
            exportedDataSet.Tables[0].Rows.Add(newRow);
            return exportedDataSet;
        }

        /// <summary>
        /// List of dictionaries to dataset
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="currentList"></param>
        /// <returns></returns>
        public static DataSet ToDataSet<TKey,TValue>(this IList<Dictionary<TKey,TValue> currentList)
        {
            DataSet exportedDataSet = new DataSet();
            DataTable exportedDataTable = exportedDataSet.Tables.Add();



            foreach (Dictionary<TKey, TValue> currentDictionary in currentList.Cast<Dictionary<TKey,TValue>>())
            {
                foreach (TKey key in currentDictionary.Keys)
                {
                    if (!exportedDataTable.Columns.Contains(key.ToString()))
                        exportedDataTable.Columns.Add(key.ToString());
                }
                DataRow newRow = exportedDataTable.NewRow();
                foreach (KeyValuePair<TKey, TValue> entry in currentDictionary)
                {
                    string key = entry.Key.ToString();

                    string val = string.Empty;
                    if (entry.Value != null)
                    {
                        val = entry.Value.ToString();
                    }

                    newRow[key] = val;

                }
                exportedDataSet.Tables[0].Rows.Add(newRow);
            }

            return exportedDataSet;
        }



    }
}

Ответы [ 3 ]

3 голосов
/ 15 ноября 2010

Обычно вам не нужно явно определять аргументы универсального типа, используемые при вызове универсального метода. Типы будут подразумеваться типами аргументов, которые вы вызываете. Если есть двусмысленность, компилятор сообщит вам.

например.,

IDictionary<string, string> myExampleDictionary = ...;
DataSet myExampleDataSet = myExampleDictionary.ToDataSet();
// equivalent to:          myExampleDictionary.ToDataSet<string, string>();

IDictionary<string, int> anotherDictionary = ...;
DataSet anotherDataSet = anotherDictionary.ToDataSet();
// equivalent to:        anotherDictionary.ToDataSet<string, int>();

Упс, я не понял, что вы перегружены ToDataSet(). Я видел только первый, который занял сингл IDictionary<TKey, TValue>.

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

public static DataSet ToDataSet<TKey, TValue>(this IList<IDictionary<TKey, TValue>> currentList)
{
    // ...
}

Здесь есть только 2 неизвестных типа, TKey и TValue, и это будет подразумеваться как обычно.

IList<IDictionary<string, string>> myList = ...;
DataSet myDataSet = myList.ToDataSet();
// equivalent to:   myList.ToDataSet<string, string>();

IDictionary<string, int> anotherList = ...;
DataSet anotherDataSet = anotherList.ToDataSet();
// equivalent to:        anotherList.ToDataSet<string, int>();
0 голосов
/ 15 ноября 2010

При вызове метода не нужно указывать типы:

IDictionary<string, int> test = new Dictionary<string, int>();
// later on.
test.ToDataSet(); // is already valid
0 голосов
/ 15 ноября 2010

Джефф М прав насчет избыточности указания общих аргументов типа для вашего первого метода.

К сожалению, сигнатура второго метода такова, что компилятор не сможет вывестивведите аргументы.Один из вариантов - изменить подпись на:

public static DataSet ToDataSet<TKey,TValue>
   (this IList<Dictionary<TKey,TValue>> currentList)

и удалить избыточный вызов на Enumerable.Cast.

. Это будет иметь 2 преимущества:

  1. Вам не нужно явно указывать аргументы универсального типа, вычислитель типа это выяснит.
  2. Поскольку приведение не выполняется, операция становится безопасной по типу, поэтому вы не сможетепередать List<int> в качестве аргумента.

С этими двумя изменениями вы можете сделать:

Dictionary<string, int> dict = ...
DataSet dictDs = dict.ToDataSet();

List<Dictionary<long, object>> list = ...
DataSet listDs = list.ToDataSet();
...