Is there any way to do this kind of casting in a C # predicate

I am trying to create a generic method that will return a predicate for finding 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.");
    }
} 

The only thing is that this does not compile. The problem is the part (T)x.Attribute(criterion.PropertyName)where the compiler points out:

Cannot express an expression like 'System.Xml.Linq.XAttribute' to type 'T'

Currently, I have two methods that are identical, except that one gives doubles and the other gives decimal. I would really like not to have such duplication.

+5
source share
6 answers

XAttribute Class . , T .

, :

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();
}

:

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));
+1

T dynamic, . , , , , , XML , .

+1

T? XAttribute , - . , , Attribute().Value, . . criterion.PropertyValue?

XML , , . , double.TryParse(). , , TryParse. , T.TryParse. , . , , .

0

T ==, object.Equals() .

To do the conversion, you can use Convert.ChangeType():

case CriteriaOperator.Equal:
    return x => object.Equals(
        Convert.ChangeType(x.Attribute(criterion.PropertyName).Value, typeof(T)),
        criterion.PropertyValue);

The problem is that in some cases, XML uses different rules for conversions (for example, it Double.PositiveInfinityappears like INF).

To solve this problem, you can use a classXmlConvert that is used by internal conversion operators. In addition, it does not have a β€œgeneral” method, such as Convert.ChangeType(), so you will need to create your own:

private static object Convert(string value, Type targetType)
{
    if (targetType == typeof(double))
        return XmlConvert.ToDouble(value);

    …

    throw new ArgumentException();
}

…

case CriteriaOperator.Equal:
    return x => object.Equals(
        Convert(x.Attribute(criterion.PropertyName).Value, typeof(T)),
        criterion.PropertyValue);
0
source

Add XAttributecontrait to the general method:

 GetPredicate<T>(Criterion criterion) where T : XAttribute
-1
source

All Articles