【问题标题】:c# LINQ Dictionary of anonymous type valuesc# LINQ 匿名类型值字典
【发布时间】:2017-06-28 10:56:54
【问题描述】:

我正在尝试准备一个字典,其中包含 COLUMN_NAME 作为键和 {IS_NULLABLE, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH} 作为值。

这是我到目前为止所做的。

Dictionary<string, object> dict = new Dictionary<string, object>();

var dt = GetDataTable($"SELECT COLUMN_NAME, IS_NULLABLE, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='{tableName}'");
if (dt != null)
{
    dict = dt.AsEnumerable().ToDictionary(row => row.Field<string>(0), row => new { IS_NULLABLE = row.Field<bool>(1), DATA_TYPE = row.Field<string>(2), CHARACTER_MAXIMUM_LENGTH = row.Field<int>(3) });
}

GetDataTable 函数未在此处列出,可以正常工作并返回一个有效的System.Data.DataTable

编译器抛出...

错误 CS0029:无法将类型“System.Collections.Generic.Dictionary>”隐式转换为“System.Collections.Generic.Dictionary”

问题是,如何生成具有这些属性的匿名对象 - IS_NULLABLE, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH?

【问题讨论】:

  • 你为什么不创建一个类DbColumn呢?那么你的字典就是Dictionary&lt;string, DbColumn&gt;
  • 是的,这很容易解决。我知道。但我想使用匿名类型来实现这一点。
  • 为什么?这不仅仅是一个修复,它是一种更好的方法,因为您可以将该字典用作类中的字段或将其作为参数传递。您也可以稍后扩展它或提供方法。与object 相比,您还具有编译时安全性,并且无需强制转换即可访问属性。
  • 以后不需要扩展了。它是临时对象,我只想检查列是否确认数据类型和字符限制。如果可以使用匿名类型进行管理,我不想在我的项目中再添加一个类。

标签: c# linq dictionary


【解决方案1】:

如果你没有在方法外返回字典,你不需要声明它。

    var dt = GetDataTable(@"SELECT COLUMN_NAME, IS_NULLABLE, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='{tableName}'");
    var dict = dt?.AsEnumerable()?.ToDictionary(row => row.Field<string>(0), row => new { IS_NULLABLE = row.Field<bool>(1), DATA_TYPE = row.Field<string>(2), CHARACTER_MAXIMUM_LENGTH = row.Field<int>(3) });

你会得到Dictionary&lt;string, anonymous type&gt;

你可以使用你的类型:

if(dict["key"].IS_NULLABLE) MessageBox.Show("yeah....");

【讨论】:

  • 字典声明是我代码中的主要问题。将此标记为答案,因为这是确定主要问题的第一个答案。
【解决方案2】:

在我看来,创建一个 DbColumn 类会更好。那么你的字典是Dictionary&lt;string, DbColumn&gt;,你也可以将它用作字段或将它传递给其他方法,你不必像Object那样每次都强制转换所有内容。您还可以使用其他属性或方法扩展该类。

但是,如果您在该方法中只需要此字典,最好将其存储在 Dictionary&lt;string, Object&gt; 中以避免强制转换。

因此你可以使用var:

var dt = GetDataTable($"SELECT COLUMN_NAME, IS_NULLABLE, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='{tableName}'");
if (dt != null)
{
    var dict = dt.AsEnumerable().ToDictionary(row => row.Field<string>(0), row => new { IS_NULLABLE = row.Field<bool>(1), DATA_TYPE = row.Field<string>(2), CHARACTER_MAXIMUM_LENGTH = row.Field<int>(3) });
    // here you can access all properties of the anonymous type without having to cast
}

当然,这仅在您只需要在 if 中使用它时才有效,似乎就是这种情况。

【讨论】:

    【解决方案3】:

    您必须将匿名对象显式转换为 object 类型,如下所示:

    dict = dt.AsEnumerable().ToDictionary(row => row.Field<string>(0), row => (object)new { IS_NULLABLE = row.Field<bool>(1), DATA_TYPE = row.Field<string>(2), CHARACTER_MAXIMUM_LENGTH = row.Field<int>(3) });
    

    因为否则编译器会创建不同类型的字典。

    【讨论】:

      【解决方案4】:

      只需将您的新匿名对象强制转换为object,您就无法将泛型类从一种类型转换为另一种本机类型。

      dict = dt.AsEnumerable()
          .ToDictionary(row => row.Field<string>(0),
               row => (object)new // Here, we cast the result to object, so the dictionary will actually use the type 'object' and not 'anonymous type'
                   {
                       IS_NULLABLE = row.Field<bool>(1),
                       DATA_TYPE = row.Field<string>(2),
                       CHARACTER_MAXIMUM_LENGTH = row.Field<int>(3)
                   });
      

      确实,您的ToDictionary 调用不会返回Dictionary&lt;string, object&gt;,而是返回Dictionary&lt;string, anonymous type&gt;。即使anonymous type 派生自object,也不能使用泛型类型进行转换(因此,使用字典)。

      不过,您将无法使用 object 访问匿名类型的属性,因此您应该改用 dynamic

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-11-07
        • 2012-04-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多