使用匿名对象列表查询数组

Posted

技术标签:

【中文标题】使用匿名对象列表查询数组【英文标题】:Querying a Array with list of anonymous Object 【发布时间】:2021-04-17 03:45:43 【问题描述】:

在我的应用程序中,我有一个对象数组, 所有对象的类型将始终相同但未知,但我需要根据某些条件更新数组对象的一个​​属性

我尝试使用反射来实现与下面相同的功能

  Public Shared Sub FilterobjectArray(ByVal obj As Object())
     
            Dim r = obj.Where(Function(x) CStr(x.[GetType]().GetProperty("Id")?.GetValue(x)) = "2")

            For Each item In r
                Dim propertyInfo As PropertyInfo = item.[GetType]().GetProperty("CompanyName")
                propertyInfo.SetValue(item, Convert.ChangeType("MyCompany", propertyInfo.PropertyType), Nothing)
            Next           
    End Sub

问题 我认为过滤数组的 Lambda 表达式是错误的,因为它在 x 中抛出“未设置对象引用”

我的示例实现

公司实体

Public Class Company
    Public Property Id As Integer
    Public Property CompanyName As String
End Class

实施

    Dim comp(2) As Object
    Dim comp1 = New Company With .Id = 1, .CompanyName = "Comp1"
    Dim comp2 = New Company With .Id = 2, .CompanyName = "Comp2"
    comp(0) = comp1
    comp(1) = comp2
    FilterobjectArray(comp)

有人可以提出什么问题吗,也欢迎 C# 答案或语法

注意:在 for 循环中第一次迭代后出现错误 即在第一个“propertyInfo.SetValue”完成并且下一次迭代开始之后

【问题讨论】:

为什么需要使用反射?你不能简单地使用一个界面来代替吗? 因为我们不知道对象的类型,所以我们使用反射来根据属性值进行过滤 您没有将任何项目添加到数组中。当您将数组传递给FilterobjectArray 时,该数组具有三个Nothing 值。 我使用Telerik Code converter 将您的 VB 代码转换为 C#,它确实将其转换为具有 3 个插槽的对象数组。而且它们都没有设置。 @SreenathGanga 我会重复彼得的评论。为什么不使用接口?如果您知道属性的名称,那么您已经对类型足够了解。你不需要反思。充其量,您需要过滤不实现接口的对象,例如OfType<>() 【参考方案1】:

这是您需要的代码:

Sub Main
    Dim comp(1) As Object
    comp(0) = New Company With .Id = 1, .CompanyName = "Comp1"
    comp(1) = New Company With .Id = 2, .CompanyName = "Comp2"

    FilterobjectArray(comp)
End Sub

Public Shared Sub FilterobjectArray(ByVal obj As Object())
    Dim r = obj.Where(Function(x) CStr(x.[GetType]().GetProperty("Id")?.GetValue(x)) = "2")
    For Each item As Object In r
        Dim propertyInfo As PropertyInfo = item.[GetType]().GetProperty("CompanyName")
        propertyInfo.SetValue(item, Nothing)
    Next
End Sub

您需要先将元素添加到数组中。其他大部分都很好,我只是简化了SetValue 调用。

【讨论】:

谢谢.. 但这不是问题,我已经完成了数组填充实际代码但忘记在 SO 中添加它。抱歉,我已经更新了问题,还添加了错误消息 第一个“propertyInfo.SetValue(item,Nothing)”后出现错误 谢谢..在阅读了彼得和凯乌斯之后我明白了你的意思【参考方案2】:

与在 C# 中声明数组大小的地方不同,在 VB 中声明数组时,需要指定最后一个有效索引。这意味着声明为 object(2) 的数组有 3 个插槽 - 0(数组从 0 开始)、1 和 2。您放置了 2 个对象,因此第三个插槽为空。

然后 ForEach 命中第三个空槽,但有一个转折:

错误窗口告诉你 x 什么都不是,x 是 LINQ 查询中使用的变量。 LINQ 查询不会在您说Where 的行上运行,它会在您使用 ForEach 中的变量 r 时立即运行。所以看起来它是导致错误的第一项,因为 ForEach 正在爆炸,但事实并非如此:事实是 LINQ 执行(将在第三个插槽上遇到错误)被延迟,直到您枚举 LINQ 查询的结果。如果您在 Where 末尾添加 .ToList() 调用,则代码将在您的 ForEach 之前崩溃..

将另一个对象添加到索引 2 中的数组中,将数组减少为 object(1) 或提供一些保护以防止 x 为 Nothing,如果您的系统在运行时自然会遇到空对象

【讨论】:

以上是关于使用匿名对象列表查询数组的主要内容,如果未能解决你的问题,请参考以下文章

匿名对象

匿名对象

匿名对象

csharp 匿名对象和列表(C#)。cs

将实体类/匿名对象转换为SqlParameter列表

将实体类匿名对象转换为SqlParameter列表