动态linq:有没有办法通过索引访问对象数据?
我需要使用 Dynamic Linq 进行一些内存中过滤。 我的对象只有一个索引器:
public object this[int index] { }
对我的数据的访问类似于: object[0], object[1],...
所以我的查询是这样的:
// get FilterText from user at runtime
// eg. filterText can be: [0] > 100 and [1] = "wpf"
collection.AsQueryable().where(filterText);
有什么方法可以做到这一点吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我有一些消息要告诉你。
这实际上是可能的......但是! (是的,有但是)。
我假设您正在使用动态 Linq 库。然后,您必须使用“it”关键字才能指定要应用索引操作的当前对象。
但是...您的索引器的返回数据类型是对象,因此您将无法编写 [0] > 100 和 [1] = "wpf" 因为数据类型不匹配。
此外,即使您从 DynamicObject 派生并在运行时添加属性,这些属性也不会在运行时由处于当前状态的动态 linq 库解析。您只会得到类型 xxx 中不存在的字段或属性。
对此有多种解决方案,其中一些您可能会接受。
一个丑陋的解决方案,如果你的数据类型数量有限,比如 n
(其中 n < .NET 中的类型数),您可以使用 n
具有参数匹配的索引器并获取您想要的数据类型。为了
例如,如果您主要有整数和一些字符串:
<前><代码>it[0]> 100 AND it[1, "dummy"] = "wpf" //虚拟参数允许您指定返回类型。
另一个丑陋的解决方案,Dynamic Linq 支持使用
ToString() 和 Convert 方法,因此,您可以编写
与上面相同的查询:
第三个丑陋的解决方案,您可以使用包装的约定
语句以告诉您如何转换数据的方式。为了
例如,你可以写:
<前><代码>it[0]> 100 与它{1} =“wpf”
并将“it[”替换为“Convert.ToDouble(it[”等...
如果我是正确的,我认为您也不能在库中使用通用索引器。并且Convert.ChangeType 在这种情况下对你没有好处,因为返回类型仍然是对象,
也许我或其他人会重写库来支持这些类型的事情,但我在不久的将来没有时间这样做(有些)。几周)
好吧,我很抱歉,但是 。我必须在 15 分钟内到达某个地方,所以我希望我们稍后会采取更好的解决方案!
将自己传送到会议
更新:
我想我可以!已经找到了您(和我的)问题的解决方案!
在 DLINQ 库中,您可以在 IxxxSignatures 接口中添加您希望能够使用的类型的成员,
因此,我添加了 (for.示例)中IEqualitySignatures:
并像这样修改了 else 块中的(在本例中)ParseComparison 方法
并且,无论您相信与否,它都有效:)
我没有测试所有类型的操作,因为我没有添加其他操作的签名 。类型和操作,但是应该非常简单!
更新
更新了上面的一些小东西。
我正在对此进行更多实验,虽然它可能也不是最漂亮的解决方案,但你可以这样做(DataObject只是一个带有索引器的DynamicObject) :
以及某种格式方法,例如(假设我已经编写了完整的方法):
我们当然可以有一个扩展方法。
或者...我们可以使用类似的方法将方法放入 DLINQ 库中(尽管这并不是一个好主意):
实现了字符串索引器,当然,类似于(忽略此处的 IndexerName 属性):
并且,检查该类型是否 将使“普通用户”能够写:
好吧,也许把这些东西放在那里不好,但你明白了。你可以有! :)
I have some news for you.
It is actually possible... BUT! (Yes, there´s a but).
I assume you are using the dynamic Linq library. You must then use the "it"-keyword to be able to specify the current object to which you wish to apply your indexing operation.
However... The return datatype of your indexer is object, so you will not be able to write [0] > 100 and [1] = "wpf" because of data type mismatch.
Also, even if you derive from DynamicObject and would add the properties at runtime, those properties would not be resolved at runtime by the dynamic linq library in it´s current state. You would just get a field or property does not exist in type xxx.
There are several solutions to this, of which some you may accept as being a solution.
One ugly solution, if you have a limited number of datatypes, say n
(where n < the number of types in .NET), you could use n
indexers with parameter matching and get the datatype you want. For
example if you have mostly ints and some strings:
Another ugly solution, Dynamic Linq has support for using the
ToString() and Convert-methods, so, you could for instance write the
same query as above:
A third ugly solution, you could use a convention where you wrap
statements in a way which tells you how to convert the data. For
example, you could write:
And replace "it[" with "Convert.ToDouble(it[" and so on...
If I´m correct, I think that you can´t use a generic indexer with the library either. And Convert.ChangeType does you no good in this case since the return type is still object.
Maybe I or someone else will rewrite the library some time to support these kinds of things, but I have no time to do so in the near future (some weeks).
Well, I´m sorry, but I´ve got to be somewhere in 15 min, so we´ll have to take the nicer solutions later I hope!
teleporting myself to the meeting
UPDATE:
I think I may have found a solution to your (and my) problem!
In the DLINQ library, you could add a member in the IxxxSignatures interface(s) for the type for which you would want to be able to work with.
So, I added (for example) in the IEqualitySignatures:
And modified the (in this case) ParseComparison-method in the else block like this.
And, believe it or not, it worked :)
I have not tested all kinds of operations, since I have not added the signatures for the other types and operations, but it should be quite straight forward to do!
UPDATE
Updated some minor stuff above..
I´m experimenting some more on this and while it might not be the prettiest solution either, you could do something like this (DataObject is just a DynamicObject with an indexer):
And some kind of format method like (pretend I´ve written a complete method):
We could of course have an extension-method instead.
Or... We could put the method in the DLINQ lib using something like (not saying it a good idea though):
And, check if the type implements a string-indexer of course, something like (ignoring IndexerName attribute here):
which would enable "normal users" to write:
Well, maybe it´s not good to have that stuff in there, but you get the point. You could have! :)
您可以使用 DynamicLinq http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx 或者您使用反射构建表达式树。为此,很多人更喜欢 Dynamic Linq 库;我自己从未使用过它,我采用了反射方法。
You either use DynamicLinq http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx or you build your expression trees using reflection. A lot of people prefer the Dynamic Linq library for this; I've never used it myself, I've taken the reflection approach.
您只需在索引器前面添加
it
,这在 DynamicLinq 语言中相当于 C# 中的this
。因此,您只需要
it[1] == "wpf"
。但是,由于索引器返回
object
,因此情况变得更加复杂。对于类类型(包括string
),你没问题,DLinq 将根据需要提升所有内容。但是,对于像
int
这样的值类型,您必须执行Int32(it[0]) > 10.
.You just need to prepend your indexer with
it
which is equivalent in DynamicLinq language tothis
in C#.So, you just need
it[1] == "wpf"
.However, there is some more complication due to the fact your indexer returns
object
. For class types (includingstring
) you are fine, DLinq will promote everything as needed.However, for value types like
int
s, you will have to doInt32(it[0]) > 10
.