有没有办法在ac#谓词中进行这种转换

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,另一个转换为十进制.我真的不希望有这种重复.

dtb*_*dtb 1

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)