Dynamic Linq - execute a request for an object with elements of type "dynamic"

I'm trying to use a dynamic linq query to retrieve an IEnumerable <T> from a collection of objects (Linq to Object), each of the objects in the collection has an internal collection with a different set of objects where the data is stored, these values ​​are accessed through an indexer from the external collection

The linq dynamic query returns a filtered set as expected when you work with strongly typed objects, but my object stores data in an element of type Dynamic , see the example below:

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"), new Data("Age", 30), new Data("BirthDate", new DateTime(1982, 1, 10)) } }; IEnumerable<DataItem> result = repository.AsQueryable<DataItem>().Where("it[\"Age\"] == 30"); if (result.Count() == 1) Console.WriteLine(result.Single()["Name"]); } 

When I run the above example, I get: The operator '==' is incompatible with the operand types "Object" and "Int32"

Are dynamic members incompatible with Dynamic Linq queries ?, or is there another way to build expressions that will be evaluated correctly when working with elements of type Dynamic

Many thanks for your help.

+7
source share
3 answers

Are dynamic members incompatible with Linq dynamic queries ?, or is there another way to build expressions that will be evaluated correctly when working with elements of type Dynamic ?

Both can work together. Just do the conversion to Int32 before doing the comparison as follows:

 IEnumerable<DataItem> result = repository.AsQueryable<DataItem>().Where("Int32(it[\"Age\"]) == 30"); 

Edit 1: Having said that, the use of dynamic binding in connection with Linq is generally limited, since dynamic operations are not allowed in expression trees. Consider the following Linq-To-Objects query:

 IEnumerable<DataItem> result = repository.AsQueryable(). Where(d => d["Age"] == 30); 

This piece of code will not compile for the above reason.

Edit 2: In your case (and in combination with Dynamic Linq), there are several ways to hack yourself around the issues mentioned in Edit 1 and in the original question. For example:

 // 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", "Mike"), new Data("Age", 25), new Data("BirthDate", new DateTime(1987, 1, 5)) }, new DataItem() { new Data("Name", "Steve"), new Data("Age", 30), new Data("BirthDate", new DateTime(1982, 1, 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", new DateTime(1982, 1, 10)); // Prints "Steve" p.DynamicQueryExample("Name", "Mike"); // Prints "Steve" (nah, just joking...) 

or

 // 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", "Mike"), new Data("Age", 25), new Data("BirthDate", new DateTime(1987, 1, 5)) }, new DataItem() { new Data("Name", "Steve"), new Data("Age", 30), new Data("BirthDate", new DateTime(1982, 1, 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, property, 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, 1, 10)"); p.DynamicQueryExample("Name", "Mike"); 
+2
source

Have you tried it[\"Age\"].Equals(object(30)) ?

Thus:

 IEnumerable<DataItem> result = repository.AsQueryable<DataItem>().Where("it[\"Age\"].Equals(object(30))"); 

Edit: updated to correctly apply 30 to the object.

+1
source

Is the code below useful to you?

 IEnumerable<DataItem> result = repository.AsQueryable<DataItem>().Where("it[\"Age\"].ToString() == \"30\""); 

But for this, all your types that can be assigned to the Value member of your Data class must have a useful implementation of the ToString method.

+1
source

All Articles