我有一些消息要告诉你。
这实际上是可能的......但是! (是的,有一个但是)。
我假设您正在使用动态 Linq 库。然后,您必须使用“it”关键字才能指定要应用索引操作的当前对象。
但是...索引器的返回数据类型是对象,因此由于数据类型不匹配,您将无法编写 [0] > 100 和 [1] = "wpf"。
此外,即使您从 DynamicObject 派生并在运行时添加属性,这些属性也不会在运行时由处于当前状态的动态 linq 库解析。您只会得到类型 xxx 中不存在的字段或属性。
对此有多种解决方案,其中一些您可能会接受。
-
一个丑陋的解决方案,如果你的数据类型数量有限,比如 n
(其中 n
it[0] > 100 AND it[1, "dummy"] = "wpf" //The dummy parameter allows you to specify return type.
-
另一个丑陋的解决方案,Dynamic Linq 支持使用
ToString() 和 Convert 方法,因此,您可以编写
与上面相同的查询:
Convert.ToDouble(it[0]) > 100 AND it[1].ToString() = "wpf".
-
第三个丑陋的解决方案,你可以使用一个约定来包装
语句以告诉您如何转换数据的方式。为了
例如,你可以写:
it[0] > 100 AND it{1} = "wpf"
并将“it[”替换为“Convert.ToDouble(it[”等...
如果我是正确的,我认为您也不能在库中使用通用索引器。在这种情况下,Convert.ChangeType 对您没有任何好处,因为返回类型仍然是对象。
也许我或其他人会在一段时间内重写库来支持这类事情,但我在不久的将来(几周)没有时间这样做。
好吧,很抱歉,但我必须在 15 分钟内到达某个地方,所以我希望我们稍后会采取更好的解决方案!
将自己传送到会议现场
UPDATE:
我想我可能已经找到了解决您(和我)问题的方法!
在 DLINQ 库中,您可以在 IxxxSignatures 接口中添加您希望使用的类型的成员。
因此,我在 IEqualitySignatures 中添加(例如):
void F(Object x, Int32 y);
并像这样修改了 else 块中的(在本例中)ParseComparison 方法。
left = Expression.Convert(left, right.Type);
而且,不管你信不信,它确实有效:)
我没有测试所有类型的操作,因为我没有添加其他类型和操作的签名,但它应该是非常简单的!
UPDATE
更新了上面的一些小东西。
我正在对此进行更多实验,虽然它可能也不是最漂亮的解决方案,但您可以执行类似的操作(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'")
好吧,也许把这些东西放在那里不太好,但你明白了。你可以有! :)