简体   繁体   English

在 C# 中,如何访问包含包裹在“对象”类型中的匿名类型项的字典

[英]In C#, how to access a dictionary with items of anonymous type wrapped inside of an "object" type

In C#, I am reading a property Config of type IDictionary<string, object> .在 C# 中,我正在读取IDictionary<string, object>类型的属性Config I am unable to access the information inside the object elements.我无法访问object元素内的信息。 It should be a JSON string, however it is wrapped as object.它应该是一个 JSON 字符串,但它被包装为对象。

In VisualStudio's Immediate window, typing Config outputs:在 VisualStudio 的立即窗口中,输入Config输出:

Count = 1
    [0]: {[items, Count = 3]}

Drilling down into items:深入研究项目:

var configItemsElement  = Config["items"]

Typing configItemsElement in Immediate window outputs:在立即窗口输出中键入configItemsElement

Count = 3
    [0]: {[1, {{ value = SeoChoiceInherit, sortOrder = 1 }}]}
    [1]: {[2, {{ value = SeoChoiceYes, sortOrder = 2 }}]}
    [2]: {[3, {{ value = SeoChoiceNo, sortOrder = 3 }}]}

and typing configItemsElement.ToString() returns this type information:并键入configItemsElement.ToString()返回此类型信息:

System.Collections.Generic.Dictionary`2[System.String,<>f__AnonymousType7`2[System.String,System.Int32]]

This is as far as I get.这是我所得到的。 I cannot access the elements of configItemsElement .我无法访问configItemsElement的元素。 For instance例如

configItemsElement[1]

results in error CS0021: Cannot apply indexing with [] to an expression of type 'object'导致error CS0021: Cannot apply indexing with [] to an expression of type 'object'

In VisualStudio's "Autos" window, the information for configItemsElement is在 VisualStudio 的“Autos”窗口中, configItemsElement的信息是

configItemsElement
Value: Count = 3
Type: object {System.Collections.Generic.Dictionary<string, <>f__AnonymousType7<string, int>>}

What does this type information mean?这个type信息是什么意思? It hints at a dictionary, yet applying a key with configItemsElement[1] results in the error above.它暗示了一个字典,但应用带有configItemsElement[1]的键会导致上述错误。 How can I cast this object to a type I can use?如何将此对象转换为我可以使用的类型? Any cast I try results in errors.我尝试的任何演员表都会导致错误。

EDIT: I have no access to the code providing the .Config property, but I can see in SQL explorer the data being read into the property.编辑:我无权访问提供.Config属性的代码,但我可以在 SQL 资源管理器中看到正在读入属性的数据。 SQL Explorer shows this data: SQL Explorer 显示以下数据:

{"items":[{"id":1,"value":"SeoChoiceInherit"},{"id":2,"value":"SeoChoiceYes"},{"id":3,"value":"SeoChoiceNo"}]}

Making configItemsElement dynamic, and accessing .value , as suggested in symap's answer, like:使configItemsElement动态化,并访问.value ,如 symap 的回答中所建议的,例如:

dynamic configItemsElement = Config["Items"];
var myString =configItemsElement.value;

results in error:导致错误:

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

which I understand, since configItemsElement should contain a dictionary .我理解,因为configItemsElement应该包含一个 dictionary 。 But, as mentioned above, accessing dictionary elements doesn`t work either.但是,如上所述,访问字典元素也不起作用。

The type System.Collections.Generic.Dictionary<string, <>f__AnonymousType7<string, int>> means that you have a dictionary where the keys are strings and the values are anonymous types . System.Collections.Generic.Dictionary<string, <>f__AnonymousType7<string, int>>表示您有一个字典,其中键是字符串,值是匿名类型 Since anonymous types have no name (from C#'s perspective anyway, as you can see they get a generated name in the compiled code) there's no usable type for you to cast the values to.由于匿名类型没有名称(无论如何,从 C# 的角度来看,正如您所看到的,它们在编译代码中获得了生成的名称),因此您没有可用的类型来将值转换为。

Your issue occurred at the point where the configuration was parsed from JSON.您的问题发生在从 JSON 解析配置时。 Anonymous types should generally only be used inside if a single methods.匿名类型一般应该只在单个方法内部使用。 If they leak out as object references you get the problems that you are having.如果它们作为object引用泄漏,您就会遇到问题。 If possible the code that generated those configuration elements should be fixed to use a named type.如果可能,生成这些配置元素的代码应该固定为使用命名类型。

However if that's no possible your only fallback is to cast the values dynamic .但是,如果这是不可能的,那么您唯一的后备方法就是将值转换为dynamic

You can use a dynamic to access the members without type checking.您可以使用动态访问成员,而无需进行类型检查。

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

so your所以你的

var configItemsElement  = Config["items"];

would become会成为

dynamic configItemsElement = Config["Items"];
var myString =configItemsElement.value;

Looking at your question the data does not appear to be stored as Json.查看您的问题,数据似乎没有存储为 Json。 If you need it as json then you would need to reconstruct the json.如果您需要它作为 json,那么您需要重建 json。 You could probably use a json Serializer您可能可以使用 json Serializer

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

I answer my own question since the valuable input I received pointed me to the right direction, yet did not give me a working solution.我回答了我自己的问题,因为我收到的宝贵意见为我指明了正确的方向,但没有给我一个可行的解决方案。 I am rather new to Stackoverflow, so if there is something I should learn about this, please let me know.我是 Stackoverflow 的新手,所以如果有什么我应该了解的,请告诉我。

Also, although I found a working solution, I do not understand why the suggestions by @symaps and @shf301 do not work in this case.另外,虽然我找到了一个可行的解决方案,但我不明白为什么 @symaps 和 @shf301 的建议在这种情况下不起作用。 This is why I am grateful for further input.这就是为什么我感谢进一步的投入。

The way I finally got it to work is to:我最终让它工作的方式是:

  • declare my own type for the anonymous type为匿名类型声明我自己的类型
  • cast configItemsElement to IEnumerableconfigItemsElement为 IEnumerable
  • iterate over the dictionary inside of configItemsElement遍历configItemsElement的字典
  • get the 'inner item' of each dictionary item using reflection使用反射获取每个字典项的“内部项”
  • cast the 'inner item' (of anonymous type) to dynamic将“内部项目”(匿名类型)转换为动态
  • and use reflection to access the 2 properties of the 'inner item' ( value and sortOrder ) to add them to a new list并使用反射访问“内部项目”的 2 个属性( valuesortOrder )以将它们添加到新列表中

This is my working code:这是我的工作代码:

...

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)
    });
}
...

Thanks to @symaps for pointing out that dynamics need to be used.感谢@symaps 指出需要使用动态。 Thanks to @shf301 for explaining that the anonymous type is the cause of the difficulty.感谢@shf301 解释匿名类型是困难的原因。 This pointed me to the right direction.这为我指明了正确的方向。

However, curiously, the solution with just dynamics (without reflection) does not work as suggested, in my case, and I don't understand why this is.但是,奇怪的是,在我的情况下,仅具有动力学(无反射)的解决方案无法按建议工作,我不明白为什么会这样。

item.GetType().GetProperties()[1] reveales the name of the innerItem: item.GetType().GetProperties()[1]显示了innerItem的名称:

{<>f__AnonymousType7`2[System.String,System.Int32] Value}
    ...
    Name: "Value"

but if I try to get to innerItem through a dynamic type using the property name like this:但是,如果我尝试使用如下属性名称通过动态类型访问 innerItem:

foreach (dynamic item in configItemsElement)
{
    dynamic innerItem = item.Value;

I get an error "'System.ValueType' does not contain a definition for 'Value'"我收到错误"'System.ValueType' does not contain a definition for 'Value'"

Equally, if I try accessing innerItem.value and innerItem.sortOrder directly without reflection like so:同样,如果我尝试直接访问innerItem.valueinnerItem.sortOrder而没有反射,如下所示:

foreach (var item in configItemsElement)
{
    dynamic innerItem = item.GetType().GetProperties()[1].GetValue(item);
    listOptions.Add(new InnerItemType() { 
        value = innerItem.value, 
        sortOrder = innerItem.sortOrder
    });

gives the same error.给出相同的错误。

Do I misunderstand the works of dynamic ?我误解了dynamic的作品吗? So, although I found a working solution, I would like to fully understand the underlying problem and I am grateful for further explanation.所以,虽然我找到了一个可行的解决方案,但我想完全理解潜在的问题,我很感激进一步的解释。 Thank you!谢谢!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM