如何在 ExpandoObject 的通用列表中搜索

Posted

技术标签:

【中文标题】如何在 ExpandoObject 的通用列表中搜索【英文标题】:How to search in generic list of ExpandoObject 【发布时间】:2021-08-04 13:05:20 【问题描述】:

跟进我的previous question。我现在正试图找到一个特定的 XML 部分。例如在以下 XML (部分)

<?xml version="1.0" encoding="utf-8" ?>
<definition date="2021-04-30" version="1.01">
    <changes>
        <change number="1" date="2021-04-30" description="Added .." />
        <change number="2" date="2021-04-30" description="Changes in .." />
        <change number="3" date="2021-04-30" description="Fixed .." />
        <change number="4" date="2021-05-11" description="Added " />
    </changes>
    <general>
        <styles>
            <style name="title">
                <font name="Arial" size="12" bold="true"/>
            </style>
            <style name="general">
                <font name="Courier new" size="10" bold="true" />
            </style>
            <style name="header">
                <font name="Courier new" size="10" bold="false" />
            </style>
        </styles>
    </general>

我想找零钱 3。 我正在使用 Dandraka XML-Utilities 使 XML 成为 ExpandoObject。这应该让我很容易获得特定的价值观。例如,使用上述内容,我可以像这样获得定义日期和版本:

    Dim strXML As String
    strXML = File.ReadAllText("C:\Tools\ReportDefinitions.xml")
    Dim def As Object
    def = XmlSlurper.ParseText(strXML)
    Console.WriteLine(def.date)
    Console.WriteLine(def.version)

我想用Linq就行了:def.changes.changeList。但很简单:

def.changes.changeList.where(Function(c) c.number = "1").count()

where 部分给出错误。已经在 SO 上进行了搜索,但大多数示例都是用 C# 编写的,并且将它们翻译成 VB.net 最终会导致无法编译的结果。 假设我必须投射它,但怎么做?

在 C# 中,可以使用 Linq:
            var iet = def.changes.changeList;
            var iets = (IEnumerable)def.changes.changeList;
            var iets2 = iets.Cast<dynamic>();
            var iets3 = iets2.FirstOrDefault(p => p.number == "3");
            int iets4 = iets3.number;
            Console.WriteLine(iets4);

现在在 VB.Net 中,我可以这样做:

    Dim iet As Object = def.changes.changeList
    Dim iets = CType(def.changes.changeList, IEnumerable)

但是这一行:

            var iets2 = iets.Cast<dynamic>();

不知道如何将其转换为 VB.Net..

谢谢

【问题讨论】:

dynamic 是让 C# 让您进行后期绑定的方式。我认为 VB 中的等价物就是Cast(Of Object)。请注意,IEnumerable.Cast(Of T) 将为您提供来自 IEnumerableIEnumerable(Of T) 【参考方案1】:

我安装了 Dandraka XML 并为您找到了答案。问题是 Linq 不能只在 IEnumerable 上工作,而是需要像 IEnumerable&lt;T&gt; 这样的东西。因此,如果您将 changeList 转换为 List(Of Dandraka.XmlUtilities.ToStringExpandoObject) 类型,那么您可以在其上使用 Linq。在 Linq 函数中还有另一个对象转换,因此我们可以访问动态属性。

Dim def = XmlSlurper.ParseText(File.ReadAllText("c:\temp\data.xml"))
Console.WriteLine("Definition date " & def.date.ToString)
Console.WriteLine("Definition version " & def.version.ToString)
Console.WriteLine()
Dim list As List(Of Dandraka.XmlUtilities.ToStringExpandoObject) = def.changes.changeList
Dim number3 As Object = list.FirstOrDefault(Function(i) CType(i, Object).number = "3")
Console.WriteLine(number3.date.ToString & " - " & number3.description.ToString)
Console.ReadLine()

【讨论】:

【参考方案2】:

我不了解 Dandraka XML,这可能是一种将 xml 转换为对象的方法。我不会去那里,而是使用普通的System.Xml 库来阅读内容并使用 XPath 找到您需要的内容。所以这不是一个确切的答案,而更像是获得相同结果的替代答案。

Dim doc As New XmlDocument()
doc.Load("c:\temp\data.xml")
Dim root As XmlNode = doc.DocumentElement
Console.WriteLine("Definition date " & root.Attributes("date").Value)
Console.WriteLine("Definition version " & root.Attributes("version").Value)
Console.WriteLine()
Dim node As XmlNode = root.SelectSingleNode("changes/change[@number='3']")
Console.WriteLine(node.Attributes("date").Value & " - " & node.Attributes("description").Value)

这将为您提供以下输出

Definition date 2021-04-30
Definition version 1.01

2021-04-30 - Fixed ..

另请参阅: select nodes using xpath navigation

【讨论】:

以上是关于如何在 ExpandoObject 的通用列表中搜索的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 ServiceStack JsonSerializer 序列化 ExpandoObject?

在列表中的元素中搜索子字符串并删除该元素

Android - 在联系人列表中搜索特定电话号码

python Python - 在YAML列表中搜索要更改或插入的值

.NET 3.5 中 ExpandoObject 的替代品,开销最小

MVC控制器里面使用dynamic和ExpandoObject