【问题标题】:Dynamic Linq and generic objects - Public member 'Select' on type T not found动态 Linq 和通用对象 - 未找到类型 T 上的公共成员“选择”
【发布时间】:2018-09-12 07:41:37
【问题描述】:

我正在尝试创建一个通用方法,该方法接受一个集合对象、对象类型的字符串表示形式和一个字典(字符串、字符串),其键包含感兴趣的属性。

然后我想根据这些输入生成一个动态 linq 查询。似乎即使在将输入集合对象转换为强类型对象之后,动态 linq 也不起作用 - 它显示 Public member 'Select' on type '{T}' not found(其中 {T} 是强类型)。

这基本上是我所拥有的:

Sub Testing123(ByVal data As Object, ByVal fieldDefs As Dictionary(Of String, String), ByVal myObjectType as String, ByVal myCollectionType As String, ByVal myAssembly As String)

    ' Type of object in the collection
    Dim properties = Type.GetType(myObjectType).GetProperties().Where(Function(p) fieldDefs.ContainsKey(p.Name)).ToList()
    ' Get type of the collection object (data)
    Dim thisType = Type.GetType(String.Format("{0},{1}",myCollectionType,myAssembly))
    ' Create strongly-typed collection object
    Dim data2 = Convert.ChangeType(data, thisType)
    ' Resolve select list from input
    Dim selectVars As String = "new (" & String.Join(", ", fieldDefs.Keys.ToList()) & ")"
    ' materialise dynamic query
    Dim result = data2.Select(selectVars) ' ERROR IS HERE

    For Each r In result
        Debug.Print(r.Title & " " & r.ViewType)
    Next
End Sub

如果我传入一个强类型集合对象(例如,而不是ByVal data As ObjectByVal data as MyStrongType)并执行等效的动态 linq 查询,它就可以正常工作。但似乎输入Object,即使转换成功(已在调试会话中确认),我也会收到此错误。

请注意,集合类型是自定义对象(SharePoint CSOM 对象,以防万一),而不仅仅是List(Of T)

【问题讨论】:

  • 投反对票者:感谢任何建设性的反馈...
  • Select 方法只能在继承或实现IEnumerable(Of T) 的类型的引用上调用。如果您的引用在编译时不知道是这种类型,那么它是不允许的。如果您知道在运行时它将是该类型,那么您可以转换为该类型,然后调用Select,尽管您还需要知道T 是什么,或者声明您的方法是通用的。
  • 感谢@jmcilhinney,感谢您的帮助。我已经验证了当对象是强类型时一切正常。我的代码 is 转换为支持Select 的类型(请参阅Dim data2 = Convert.ChangeType(...))。我错过了什么吗?
  • Convert.ChangeType 不是演员表。它返回一个Object 引用。所以你试图在Object 上调用Select,这是不允许的。强制转换和转换是两个不同的东西。强制转换会更改用于访问对象的引用的类型,而转换会更改对象的类型。 Convert.ChangeType 在您需要前者时执行后者。
  • 啊,谢谢。我需要确定我是否可以动态转换 - 以前的尝试不会让我以与我在上面的 Convert.ChangeType 中传递 Type 参数的方式相同

标签: .net vb.net linq dynamic dynamic-linq


【解决方案1】:

进一步考虑,Select 的 LINQ 版本实际上必须需要 IEnumerableIQueryable 而不是 IEnumerable(Of T)。我快速浏览了一下,找不到确认,但我认为一定是这样,否则它不会是动态的。在这种情况下,您可以简单地转换为该类型,而无需对您的代码进行任何其他更改。

如果只需要IEnumerable,那么就使用这个:

Dim result = DirectCast(data2, IEnumerable).Select(selectVars)

如果需要IQueryable,那么您的对象可能还没有实现它,您需要这个:

Dim result = DirectCast(data2, IEnumerable).AsQueryable().Select(selectVars)

这个答案是有根据的猜测,但似乎合乎逻辑,所以希望它是准确的。

【讨论】:

  • 很好,谢谢 - 这对我正在做的事情有用。干杯!
猜你喜欢
  • 2021-03-10
  • 1970-01-01
  • 1970-01-01
  • 2012-02-08
  • 1970-01-01
  • 1970-01-01
  • 2012-09-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多