获取字典列表作为数据集的扩展方法?

发布于 2024-10-02 15:19:07 字数 3401 浏览 6 评论 0原文

我正在尝试将 Dictionary 对象列表转换为数据集。该列表来自 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;
        }



    }
}

I'm trying to cast a List of Dictionary objects to a dataset. The List comes from a JSON parser. I decided to use this as an opportunity to learn about extension methods.

The extension method for a single dictionary works, but the method for a List of Dictionaries doesn't "look" right to me, mainly because the call becomes

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

Am I missing something? Does it really have to be this complicated? Should I just throw the Dictionary .ToDataSet method in a 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;
        }



    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

何止钟意 2024-10-09 15:19:07

通常不需要显式定义调用泛型方法时使用的泛型类型参数。这些类型将由您调用的参数类型隐含。如果存在歧义,编译器会让您知道。

例如,

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

但无论哪种方式,第二个重载都应该具有与第一个重载相同的通用参数。它将是 IDictionaryIList,因此应该采用以下形式:

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

这里只有 2 个未知类型,TKeyTValue 这将像往常一样被暗示。

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

You generally don't need to explicitly define the generic type arguments used when calling a generic method. The types will be implied by the types of the arguments you are calling with. If there's an ambiguity, the compiler will let you know.

e.g.,

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

Oops, I didn't realize you overloaded ToDataSet(). I only saw the first one which took a single IDictionary<TKey, TValue>.

But either way, the second overload should have the generic parameters the same as the first. It will be a IList of IDictionarys so it should be in this form:

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

There are only 2 unknown types here, TKey and TValue and that will be implied as usual.

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>();
萌逼全场 2024-10-09 15:19:07

您的方法调用不需要指定类型,这将是:

IDictionary<string, int> test = new Dictionary<string, int>();
// later on.
test.ToDataSet(); // is already valid

Your method call needs not specify the types, which would be:

IDictionary<string, int> test = new Dictionary<string, int>();
// later on.
test.ToDataSet(); // is already valid
甜妞爱困 2024-10-09 15:19:07

Jeff M 关于为第一个方法指定通用类型参数的冗余的说法是正确的。

不幸的是,第二个方法的签名使得编译器无法推断类型参数。一种选择是将签名更改为:

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

并删除对 Enumerable.Cast 的冗余调用。

这将有两个好处:

  1. 您不必显式指定泛型类型参数,类型推断器会弄清楚它。
  2. 由于不涉及转换,该操作变得类型安全,因此您将无法将 List 作为参数传递。

通过这两项更改,您可以执行以下操作:

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

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

Jeff M is right about the redundancy of specifying the generic type-arguments for your first method.

Unfortunately, the signature of the second method is such that it would not be possible for the compiler to infer the type arguments. One option would be to change the signature to:

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

and to remove the redundant call to Enumerable.Cast.

This will have 2 benefits:

  1. You wan't have to explicitly specify the generic type arguments, the type-inferencer will figure it out.
  2. Since no casting is involved, the operation becomes type-safe, so you won't be able to pass a List<int> as an argument.

With these two changes, you can do:

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

List<Dictionary<long, object>> list = ...
DataSet listDs = list.ToDataSet();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文