[英]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:我最终让它工作的方式是:
configItemsElement
to IEnumerableconfigItemsElement
为 IEnumerableconfigItemsElement
configItemsElement
的字典value
and sortOrder
) to add them to a new listvalue
和sortOrder
)以将它们添加到新列表中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.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
});
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.