其他分享
首页 > 其他分享> > CodeGo.net>动态LINQ:有没有办法通过索引访问对象数据?

CodeGo.net>动态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);

有什么办法吗?

解决方法:

我有一些消息要告诉你.

实际上有可能……但是! (是的,但是有一个).

我假设您正在使用动态Linq库.然后,您必须使用“ it”关键字来指定要对其应用索引操作的当前对象.

但是…索引器的返回数据类型是object,因此您将无法写入[0]> 100和[1] =“ wpf”,因为数据类型不匹配.

同样,即使您从DynamicObject派生并在运行时添加属性,动态linq库也无法在运行时解析其当前状态的那些属性.您只会得到一个字段或XXX类型中不存在的属性.

有几种解决方案,您可以接受其中一些作为解决方案.

>一个丑陋的解决方案,如果您的数据类型数量有限,请说n
(其中n< .NET中类型的数量),则可以使用n
具有参数匹配的索引器,并获取所需的数据类型.对于
例如,如果您主要是整数和一些字符串:

it[0] > 100 AND it[1, "dummy"] = "wpf" //The dummy parameter allows you to specify return type.

>另一个难看的解决方案,Dynamic Linq支持使用
ToString()和Convert-methods,因此,您可以例如编写
与上述相同的查询:

Convert.ToDouble(it[0]) > 100 AND it[1].ToString() = "wpf".

>第三种丑陋的解决方案,您可以在包装时使用约定
陈述式,告诉您如何转换资料.对于
例如,您可以编写:

it[0] > 100 AND it{1} = "wpf"

然后将“ it [”替换为“ Convert.ToDouble(it [”,依此类推…

如果我是对的,我认为您也不能在该库中使用通用索引器.在这种情况下,Convert.ChangeType对您不利,因为返回类型仍然是对象.

也许我或其他人会花一些时间重写该库以支持这些事情,但是我没有时间在不久的将来(几周)这样做.

好吧,很抱歉,但是我必须在15分钟内到达某个地方,所以希望以后我们必须采用更好的解决方案!

将自己传送到会议上

更新:

我想我可能已经找到您(和我)问题的解决方案!

在DLINQ库中,您可以在IxxxSignatures接口中添加您想要使用的类型的成员.

因此,我在IEqualitySignatures中添加了(例如):

void F(Object x, Int32 y);

并像这样修改else块中的ParseComparison方法(在这种情况下).

left = Expression.Convert(left, right.Type);

而且,信不信由你,它有效:)

我没有测试所有类型的操作,因为我没有添加其他类型和操作的签名,但是这样做应该很简单!

更新

更新了上面的一些次要内容.

我正在对此进行更多的实验,虽然它可能也不是最漂亮的解决方案,但是您可以执行以下操作(DataObject只是带有索引器的DynamicObject):

    [TestMethod]
    public void DynamicTest()
    {
        List<DataObject> dataObjects = new List<DataObject>();

        dynamic firstObject = new DataObject();
        dynamic secondObject = new DataObject();

        firstObject.dblProp = 10.0;
        firstObject.intProp = 8;
        firstObject.strProp = "Hello";

        secondObject.dblProp = 8.0;
        secondObject.intProp = 8;
        secondObject.strProp = "World";

        dataObjects.Add(firstObject);
        dataObjects.Add(secondObject);

        /* Notice the different types */
        string newQuery = FormatQuery("dblProp > 9.0 AND intProp = 8 AND strProp = 'Hello'");

        var result = dataObjects.Where(newQuery);

        Assert.AreEqual(result.Count(), 1);
        Assert.AreEqual(result.First(), firstObject);
    }

以及某种格式方法(例如,我写了一个完整的方法):

    public string FormatQuery(string query)
    {
        query = query.Replace('\'', '\"');

        string[] operators = new string[] { "<", ">", "!=", "<=", ">=", "<>", "=" };

        string[] parts = query.Split();

        for (int i = 0; i < parts.Length; i++)
        {
            if (operators.Contains(parts[i]))
            {
                parts[i - 1] = "it[\"" + parts[i - 1] + "\"]";
            }
        }

        return String.Join(" ", parts);
    }

当然,我们可以有一种扩展方法.

或者…我们可以使用类似的方法将方法放入DLINQ库中(虽然这不是一个好主意):

if (typeof(T).GetInterface("IDynamicMetaObjectProvider", true) != null)
    whereClause = whereClause.FormatQuery();

并且,检查类型是否实现了字符串索引器,例如(在这里忽略IndexerName属性):

if (t.GetType().GetProperty("Item") != null)

这将使“普通用户”可以编写:

data.Where("dblProp > 9.0 AND intProp = 8 AND strProp = 'Hello'")

好吧,也许在那里放东西不好,但是您明白了.你可以有!

标签:dynamic-linq,indexer,casting,c
来源: https://codeday.me/bug/20191101/1986020.html