在C#中,如何使用包装在“C”中的匿名类型项访问词典;“对象”;类型

在C#中,如何使用包装在“C”中的匿名类型项访问词典;“对象”;类型,c#,C#,在C#中,我正在读取类型为IDictionary的属性Config。我无法访问对象元素中的信息。它应该是一个JSON字符串,但是它被包装为object 在VisualStudio的即时窗口中,键入Config输出: Count = 1 [0]: {[items, Count = 3]} 深入到项目: var configItemsElement = Config["items"] 在即时窗口输出中键入configItemsElement: Count = 3 [0]: {[

在C#中,我正在读取类型为
IDictionary
的属性
Config
。我无法访问
对象
元素中的信息。它应该是一个JSON字符串,但是它被包装为object

在VisualStudio的即时窗口中,键入
Config
输出:

Count = 1
    [0]: {[items, Count = 3]}
深入到项目:

var configItemsElement  = Config["items"]
在即时窗口输出中键入
configItemsElement

Count = 3
    [0]: {[1, {{ value = SeoChoiceInherit, sortOrder = 1 }}]}
    [1]: {[2, {{ value = SeoChoiceYes, sortOrder = 2 }}]}
    [2]: {[3, {{ value = SeoChoiceNo, sortOrder = 3 }}]}
并键入
configItemsElement.ToString()
返回此类型信息:

System.Collections.Generic.Dictionary`2[System.String,<>f__AnonymousType7`2[System.String,System.Int32]]
导致
错误CS0021:无法将带[]的索引应用于“object”类型的表达式

在VisualStudio的“自动”窗口中,
configItemsElement
的信息是

configItemsElement
Value: Count = 3
Type: object {System.Collections.Generic.Dictionary<string, <>f__AnonymousType7<string, int>>}
使
configItemsElement
动态,并访问
.value
,如symap的回答所示,如下所示:

dynamic configItemsElement = Config["Items"];
var myString =configItemsElement.value;
错误结果:

''object' does not contain a definition for 'value''

我理解,因为
configItemsElement
应该包含一个字典。但是,如上所述,访问dictionary元素也不起作用。

您可以使用dynamic来访问成员,而无需进行类型检查

using System;
using System.Collections;
using System.Collections.Generic;

namespace ObjectDictionary
{
    class Program
    {
        static void Main(string[] args)
        {

            IDictionary <string, object>  dict= new Dictionary<String, object>();
            dict.Add("abc", new {value = "blah", sortOrder = 1});

            dynamic a = dict["abc"];
            Console.WriteLine(a.value);
            Console.WriteLine(a.sortOrder);
        }
    }
}
将成为

dynamic configItemsElement = Config["Items"];
var myString =configItemsElement.value;
从您的问题来看,数据似乎没有存储为Json。如果您需要它作为json,那么您需要重建json。 您可能会使用json序列化程序

 string json = JsonConvert.SerializeObject(configItemsElement, Formatting.Indented);
            Console.WriteLine(json);

您可以使用动态链接来访问成员,而无需进行类型检查

using System;
using System.Collections;
using System.Collections.Generic;

namespace ObjectDictionary
{
    class Program
    {
        static void Main(string[] args)
        {

            IDictionary <string, object>  dict= new Dictionary<String, object>();
            dict.Add("abc", new {value = "blah", sortOrder = 1});

            dynamic a = dict["abc"];
            Console.WriteLine(a.value);
            Console.WriteLine(a.sortOrder);
        }
    }
}
将成为

dynamic configItemsElement = Config["Items"];
var myString =configItemsElement.value;
从您的问题来看,数据似乎没有存储为Json。如果您需要它作为json,那么您需要重建json。 您可能会使用json序列化程序

 string json = JsonConvert.SerializeObject(configItemsElement, Formatting.Indented);
            Console.WriteLine(json);

类型
System.Collections.Generic.Dictionary
表示您有一个字典,其中键是字符串,值是字符串。由于匿名类型没有名称(无论如何,从C#的角度来看,正如您可以看到的那样,它们在编译的代码中得到了一个生成的名称),因此没有可用于将值强制转换到的类型

您的问题发生在从JSON解析配置时。匿名类型通常只应在单个方法内部使用。如果它们泄漏为
对象
引用,您就会遇到问题。如果可能,生成这些配置元素的代码应该固定为使用命名类型


但是,如果不可能,您唯一的退路就是强制转换值。

类型
System.Collections.Generic.Dictionary
意味着您有一个字典,其中键是字符串,值是字符串。由于匿名类型没有名称(无论如何,从C#的角度来看,正如您可以看到的那样,它们在编译的代码中得到了一个生成的名称),因此没有可用于将值强制转换到的类型

您的问题发生在从JSON解析配置时。匿名类型通常只应在单个方法内部使用。如果它们泄漏为
对象
引用,您就会遇到问题。如果可能,生成这些配置元素的代码应该固定为使用命名类型


然而,如果这不可能,你唯一的退路就是抛出价值观。

我回答我自己的问题,因为我收到的宝贵意见为我指明了正确的方向,但没有给我一个有效的解决方案。我是Stackoverflow的新手,所以如果有什么我应该了解的,请告诉我

此外,尽管我找到了一个有效的解决方案,但我不理解@symaps和@shf301的建议在这种情况下为什么不起作用。这就是为什么我感谢进一步的投入

我最终实现这一目标的方法是:

  • 为匿名类型声明我自己的类型
  • configItemsElement
    转换为IEnumerable
  • configItemsElement
  • 使用反射获取每个字典项的“内部项”
  • 将“内部项”(匿名类型)强制转换为动态
  • 并使用反射访问“内部项”的两个属性(
    value
    sortOrder
    )以将它们添加到新列表中
这是我的工作代码:

...

public class InnerItemType
{
    public int sortOrder { get; set;  }
    public string value { get; set; }
}

....

List<InnerItemType> listOptions = new List<InnerItemType>();

var configItemsElement = Config["items"] as IEnumerable;

foreach (var item in configItemsElement)
{
    dynamic innerItem = item.GetType().GetProperties()[1].GetValue(item);
    listOptions.Add(new InnerItemType() { 
        value = innerItem.GetType().GetProperties()[0].GetValue(innerItem), 
        sortOrder = innerItem.GetType().GetProperties()[1].GetValue(innerItem)
    });
}
...
但是,如果我尝试通过使用如下属性名的动态类型访问innerItem:

foreach (dynamic item in configItemsElement)
{
    dynamic innerItem = item.Value;
我收到一个错误
“'System.ValueType'不包含'Value'的定义”

同样,如果我尝试直接访问
innerItem.value
innerItem.sortOrder
而不进行反射,如下所示:

foreach (var item in configItemsElement)
{
    dynamic innerItem = item.GetType().GetProperties()[1].GetValue(item);
    listOptions.Add(new InnerItemType() { 
        value = innerItem.value, 
        sortOrder = innerItem.sortOrder
    });
给出了相同的错误


我是否误解了
dynamic
的作品?因此,尽管我找到了一个有效的解决方案,但我希望能够充分理解潜在的问题,并感谢进一步的解释。谢谢大家!

我回答了自己的问题,因为我收到的宝贵意见为我指明了正确的方向,但没有给我一个有效的解决方案。我是Stackoverflow的新手,所以如果有什么我应该了解的,请告诉我

此外,尽管我找到了一个有效的解决方案,但我不理解@symaps和@shf301的建议在这种情况下为什么不起作用。这就是为什么我感谢进一步的投入

我最终实现这一目标的方法是:

  • 为匿名类型声明我自己的类型
  • configItemsElement
    转换为IEnumerable
  • configItemsElement
  • 使用反射获取每个字典项的“内部项”
  • 将“内部项”(匿名类型)强制转换为动态
  • 并使用反射访问“内部项”的两个属性(
    value
    sortOrder
    )以将它们添加到新列表中
这是我的工作代码:

...

public class InnerItemType
{
    public int sortOrder { get; set;  }
    public string value { get; set; }
}

....

List<InnerItemType> listOptions = new List<InnerItemType>();

var configItemsElement = Config["items"] as IEnumerable;

foreach (var item in configItemsElement)
{
    dynamic innerItem = item.GetType().GetProperties()[1].GetValue(item);
    listOptions.Add(new InnerItemType() { 
        value = innerItem.GetType().GetProperties()[0].GetValue(innerItem), 
        sortOrder = innerItem.GetType().GetProperties()[1].GetValue(innerItem)
    });
}
...
但是,如果我尝试通过使用如下属性名的动态类型访问innerItem:

foreach (dynamic item in configItemsElement)
{
    dynamic innerItem = item.Value;
我收到一个错误,“'System.ValueType'不包含'