Ser*_*ero 5 c# generics linq-to-xml
我正在尝试创建一个泛型方法,它将返回一个谓词来查找XML文档中的元素.
基本上是这样的:
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.");
}
}
Run Code Online (Sandbox Code Playgroud)
唯一的问题是这不能编译.问题出(T)x.Attribute(criterion.PropertyName)在编译器指示的部分:
无法将类型为"System.Xml.Linq.XAttribute"的表达式转换为"T"
目前我有两个相同的方法,除了一个转换为double,另一个转换为十进制.我真的不希望有这种重复.
XAttribute类定义了几个转换运算符。但是,当转换为泛型类型参数时T,不会考虑这些运算符。
您可以做的是在运行时构造 lambda 表达式,如下所示:
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();
}
Run Code Online (Sandbox Code Playgroud)
用法:
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));
Run Code Online (Sandbox Code Playgroud)