我试图使用动态
linq查询来检索IEnumerable< T>从对象集合(
Linq到Object),集合中的每个对象都有一个内部集合,其中包含存储数据的另一组对象,这些值通过外部集合中的索引器访问
当您使用强类型对象但我的对象将数据存储在动态类型的成员中时,动态linq查询会按预期返回已过滤的集,请参阅下面的示例:
public class Data { public Data(string name,dynamic value) { this.Name = name; this.Value = value; } public string Name { get; set; } public dynamic Value { get; set; } } public class DataItem : IEnumerable { private List<Data> _collection; public DataItem() { _collection = new List<Data>(); } public dynamic this[string name] { get { Data d; if ((d = _collection.FirstOrDefault(i => i.Name == name)) == null) return (null); return (d.Value); } } public void Add(Data data) { _collection.Add(data); } public IEnumerator GetEnumerator() { return _collection.GetEnumerator(); } } public class Program { public void Example() { List<DataItem> repository = new List<DataItem>(){ new DataItem() { new Data("Name","Mike"),new Data("Age",25),new Data("BirthDate",new DateTime(1987,1,5)) },new DataItem() { new Data("Name","Steve"),30),new DateTime(1982,10)) } }; IEnumerable<DataItem> result = repository.AsQueryable<DataItem>().Where("it[\"Age\"] == 30"); if (result.Count() == 1) Console.WriteLine(result.Single()["Name"]); }
当我运行上面的例子时,我得到:运算符’==’与操作数类型’Object’和’Int32’不兼容
动态成员是否与Dynamic Linq查询不兼容?还是有另一种构造表达式的方法,这些表达式在处理动态类型的成员时会正确评估
非常感谢你的帮助.
解决方法
Are dynamic members incompatible with Dynamic Linq queries?,or is there another way of constructing expressions that would evaluate properly when dealing with members of type dynamic?
两者都可以一起工作.在进行比较之前,只需转换为Int32,如下所示:
IEnumerable<DataItem> result = repository.AsQueryable<DataItem>().Where("Int32(it[\"Age\"]) == 30");
编辑1:尽管如此,与Linq相关的动态绑定的使用通常受到限制,因为表达式树中不允许动态操作.考虑以下Linq-To-Objects查询:
IEnumerable<DataItem> result = repository.AsQueryable(). Where(d => d["Age"] == 30);
由于上述原因,此代码段无法编译.
编辑2:在您的情况下(与Dynamic Linq一起),有一些方法可以解决编辑1和原始问题中提到的问题.例如:
// Variant 1: Using strings all the way public void DynamicQueryExample(string property,dynamic val) { List<DataItem> repository = new List<DataItem>(){ new DataItem() { new Data("Name",5)) },new DataItem() { new Data("Name",10)) } }; // Use string comparison all the time string predicate = "it[\"{0}\"].ToString() == \"{1}\""; predicate = String.Format(whereClause,property,val.ToString()); var result = repository.AsQueryable<DataItem>().Where(predicate); if (result.Count() == 1) Console.WriteLine(result.Single()["Name"]); } Program p = new Program(); p.DynamicQueryExample("Age",30); // Prints "Steve" p.DynamicQueryExample("BirthDate",10)); // Prints "Steve" p.DynamicQueryExample("Name","Mike"); // Prints "Steve" (nah,just joking...)
要么:
// Variant 2: Detecting the type at runtime. public void DynamicQueryExample(string property,string val) { List<DataItem> repository = new List<DataItem>(){ new DataItem() { new Data("Name",10)) } }; string whereClause = "{0}(it[\"{1}\"]) == {2}"; // Discover the type at runtime (and convert accordingly) Type type = repository.First()[property].GetType(); string stype = type.ToString(); stype = stype.Substring(stype.LastIndexOf('.') + 1); if (type.Equals(typeof(string))) { // Need to surround formatting directive with "" whereClause = whereClause.Replace("{2}","\"{2}\""); } string predicate = String.Format(whereClause,stype,val); var result = repository.AsQueryable<DataItem>().Where(predicate); if (result.Count() == 1) Console.WriteLine(result.Single()["Name"]); } var p = new Program(); p.DynamicQueryExample("Age","30"); p.DynamicQueryExample("BirthDate","DateTime(1982,10)"); p.DynamicQueryExample("Name","Mike");