0

ac#式を変換しようとしています。これが私が探している結果の例です。変換:

Expression<Func<TestObj, bool>> filter = p => p.LastName == "Smith";

これに:

Expression<Func<DynamicItem, bool>> converted = p => p.FieldID == 5 && p.FieldValue == "Smith"

以下のコードでわかるように、FieldIDは、実際にはクラスの属性の反映を介して取得されます。私が今得ているエラーは、「タイプ'System.Int32'の式はリターンタイプ'System.Boolean'には使用できません」であるConvertからのリターンです。

私は壁にぶつかって、誰かが私がここで間違っていることを見ることができるかもしれないと思いました。これが私のコードです:

public class MongoReplaceAttribute : Attribute
{
    public int FieldID { get; set; }
}

public class TestObj
{
    [MongoReplaceAttribute(FieldID = 1)]
    public string FirstName { get; set; }


    [MongoReplaceAttribute(FieldID = 2)]
    public string LastName { get; set; }
}

public class DynamicItem
{
    public int FieldID { get; set; }
    public string FieldValue { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        string v = "Smith";

        Expression<Func<TestObj, bool>> test = p => p.LastName == v;
        var list = MagicFunction(test);

        Console.ReadLine();
    }

    static IEnumerable<DynamicItem> MagicFunction(Expression<Func<TestObj, bool>> filter)
    {
        List<DynamicItem> rands = new List<DynamicItem>() 
        { 
            new DynamicItem 
            { 
                FieldID = 1, 
                FieldValue = "Bob" 
            }, 
            new DynamicItem 
            { 
                FieldID = 2, 
                FieldValue = "Smith" 
            },
            new DynamicItem 
            { 
                FieldID = 1, 
                FieldValue = "Alice" 
            }, 
            new DynamicItem 
            { 
                FieldID = 2, 
                FieldValue = "Smith" 
            } 
        };

        var f2 = Converter<DynamicItem>.Convert(filter);

        return rands.AsQueryable<DynamicItem>().Where(f2);
    }
}

class Converter<TTo>
{
    class ConversionVisitor : ExpressionVisitor
    {
        private readonly ParameterExpression newParameter;
        private readonly ParameterExpression oldParameter;

        public ConversionVisitor(ParameterExpression newParameter, ParameterExpression oldParameter)
        {
            this.newParameter = newParameter;
            this.oldParameter = oldParameter;
        }

        protected override Expression VisitLambda<T>(Expression<T> node)
        {
            return base.VisitLambda<T>(node);
        }

        protected override Expression VisitBinary(BinaryExpression node)
        {
            Expression left = this.Visit(node.Left);
            Expression right = this.Visit(node.Right);
            Expression conversion = this.Visit(node.Conversion);

            if (left != node.Left)
            {
                return base.Visit(left);
            }
            else if (right != node.Right)
            {
                var r = base.Visit(right);
                return r;
            }
            else
            {
                return node;
            }
        }

        protected override Expression VisitParameter(ParameterExpression node)
        {
            return newParameter;
        }

        protected override Expression VisitMember(MemberExpression node)
        {
            if (node.Expression != oldParameter)
            {
                return base.VisitMember(node);
            }

            var s = node.Member;
            var attrReader = s.GetCustomAttributes(typeof(MongoReplaceAttribute), true).Cast<MongoReplaceAttribute>();

            //If we are a mongo attribute
            if (attrReader != null && attrReader.Count() > 0)
            {
                var id = attrReader.First().FieldID;
                Expression<Func<DynamicItem, bool>> ret = p => p.FieldID == id && p.FieldValue == (string)GetValue(node);
                ParameterExpression param = Expression.Parameter(typeof(DynamicItem), "p");
                var lambda = Expression.Lambda<Func<DynamicItem, bool>>(ret.Body, param);
                return base.Visit(lambda.Body);
            }
            return base.VisitMember(node);
        }

        private object GetValue(MemberExpression member)
        {
            var objectMember = Expression.Convert(member, typeof(object));
            var getterLambda = Expression.Lambda<Func<object>>(objectMember);
            var getter = getterLambda.Compile();
            return getter();
        }
    }

    public static Expression<Func<TTo, TR>> Convert<TFrom, TR>(
        Expression<Func<TFrom, TR>> e)
    {
        var oldParameter = e.Parameters[0];
        var newParameter = Expression.Parameter(typeof(TTo), oldParameter.Name);
        var converter = new ConversionVisitor(newParameter, oldParameter);
        var newBody = converter.Visit(e.Body);
        return Expression.Lambda<Func<TTo, TR>>(newBody, newParameter);
    }
}
4

1 に答える 1

0

以下のコードのnewBodyは、正しく作成されていないようです。e.Bodyですp.LastName == "Smith" が、予想外newBodyです。等値比較が欠落していることに注意してください。 したがって、最後の行で、int (p.FieldId) を返すボディから の Lambda を作成しようとすると、エラーがスローされます。p.FieldIDp.FieldId==5
Func<DynamicItem, bool>

これはおそらく、ConversionVisitor のバグによるものです。ConversionVisitor をデバッグして、間違ったボディが作成される理由を確認してください。

public static Expression<Func<TTo, TR>> Convert<TFrom, TR>(
    Expression<Func<TFrom, TR>> e)
{
    var oldParameter = e.Parameters[0];
    var newParameter = Expression.Parameter(typeof(TTo), oldParameter.Name);
    var converter = new ConversionVisitor(newParameter, oldParameter);
    var newBody = converter.Visit(e.Body);
    return Expression.Lambda<Func<TTo, TR>>(newBody, newParameter);
}
于 2013-02-17T19:42:20.637 に答える