I'm trying to create a generic method that will return a predicate to find elements in an XML document.
Basically something like this:
private static Func<XElement, bool> GetPredicate<T>(Criterion criterion)
{
switch (criterion.CriteriaOperator)
{
case CriteriaOperator.Equal:
return x => (T)x.Attribute(criterion.PropertyName) ==
(T)(criterion.PropertyValue);
case CriteriaOperator.GreaterThan:
return x => (T)x.Attribute(criterion.PropertyName) >
(T)(criterion.PropertyValue);
case CriteriaOperator.GreaterThanOrEqual:
return x => (T)x.Attribute(criterion.PropertyName) >=
(T)(criterion.PropertyValue);
case CriteriaOperator.LessThan:
return x => (T)x.Attribute(criterion.PropertyName) <
(T)(criterion.PropertyValue);
case CriteriaOperator.LessThanOrEqual:
return x => (T)x.Attribute(criterion.PropertyName) <=
(T)(criterion.PropertyValue);
case CriteriaOperator.NotEqual:
return x => (T)x.Attribute(criterion.PropertyName) !=
(T)(criterion.PropertyValue);
default:
throw new ArgumentException("Criteria Operator not supported.");
}
}
Only thing is that this doesn't compile. The problem is on the (T)x.Attribute(criterion.PropertyName)
part where the compiler indicates:
Cannot cast expression of type 'System.Xml.Linq.XAttribute' to type 'T'
Currently I have two methods that are identical except that one casts to double and the other one to decimal. I would really like not to have that kind of duplication.
The XAttribute Class defines several conversion operators. However,when casting to a generic type parameter T
, these operators are not taken into consideration.
What you can do is construct the lambda expression at runtime as follows:
private static Func<XElement, bool> GetPredicate<T>(Criterion criterion)
{
var arg = Expression.Parameter(typeof(XElement), "arg");
var name = Expression.Constant((XName)criterion.PropertyName);
var attr = Expression.Call(arg, "Attribute", null, name);
var left = Expression.Convert(attr, typeof(T));
var right = Expression.Constant(criterion.PropertyValue, typeof(T));
Expression body;
switch (criterion.CriteriaOperator)
{
case CriteriaOperator.Equal:
body = Expression.Equal(left, right);
break;
case CriteriaOperator.GreaterThan:
body = Expression.GreaterThan(left, right);
break;
default:
throw new ArgumentException("Criteria Operator not supported.");
}
return Expression.Lambda<Func<XElement, bool>>(body, arg).Compile();
}
Usage:
var f = GetPredicate<int>(new Criterion("documentversion", CO.GreaterThan, 8));
var g = GetPredicate<string>(new Criterion("documentid", CO.Equal, "DOC-5X"));
var h = GetPredicate<double>(new Criterion("documentprice", CO.Equal, 85.99d));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With