简体   繁体   English

构建表达式树以调用具有 1 或 2 个参数的函数

[英]Build expression tree to call function with 1 or 2 parameters

So, experimenting with expression trees a bit.所以,尝试一下表达式树。 Here is the idea: I want to return a Func<long, byte?, object> object.这是一个想法:我想返回一个Func<long, byte?, object>对象。 Depending on the type I want to use the function on, I'll have one of two methods to use: LoadById(long, byte?) or LoadByID(long) .根据我想要使用该函数的类型,我将使用以下两种方法之一: LoadById(long, byte?)LoadByID(long) Both return an object.两者都返回一个对象。 So i'm trying to do the following: depending on whether the type implements a certain interface, I use either classToUseFunctionOn.LoadById(long, byte?) or classToUseFunctionOn.LoadByID(long) .所以我正在尝试执行以下操作:根据类型是否实现某个接口,我使用classToUseFunctionOn.LoadById(long, byte?)classToUseFunctionOn.LoadByID(long) So, basically I want to have the following code returned if it implements the interface: (long id, byte? options) => new TestFacade().LoadById(id, options) and (long id, byte? options) => new TestFacade().LoadByID(id).所以,基本上我希望如果它实现了接口,则返回以下代码: (long id, byte? options) => new TestFacade().LoadById(id, options) and (long id, byte? options) => new TestFacade().LoadByID(id)。 I'm just not sure how to do it.我只是不知道该怎么做。 It goes wrong on the last few lines.最后几行出错了。 The Lambda call states the amount of parameters is incorrect. Lambda 调用声明参数数量不正确。 Below is the code I have so far:以下是我到目前为止的代码:



    private static Func GetDataExtractorForTypeWithId(Type type)
    {
        var paramId = Expression.Parameter(typeof(long), "id");
        ParameterExpression paramOptions = null;
        //gets the ConstructorInfo for the constructor of type T with a single parameter of type IDataReader
        var facadetype = GetFacadeType(type.Name);
        MethodInfo loadMethod;
        var linkedEntitiesInterface = facadetype.GetInterface(typeof(IFacadeLoadLinkedEntities).Name);
        var lamdaParameterExpressions = new List() { paramId };
        if (linkedEntitiesInterface != null)
        {
            loadMethod = facadetype.GetMethod("LoadById");
            paramOptions = Expression.Parameter(linkedEntitiesInterface.GetGenericTypeDefinition().GenericTypeArguments[1], "options");
            lamdaParameterExpressions.Add(paramOptions);
        }
        else
        {
            paramOptions = Expression.Parameter(typeof(byte?));
            loadMethod = facadetype.GetMethod("LoadByID", new Type[1]{typeof(long)});
        }
        var facadeConstructor = facadetype.GetConstructor(new Type[0]);
        var newFacade = Expression.New(facadeConstructor);
        var callLoad = Expression.Call(newFacade, loadMethod, lamdaParameterExpressions);
        lamdaParameterExpressions.Add(paramOptions);
        var returnValue = Expression.Parameter(typeof(object));
        lamdaParameterExpressions.Add(returnValue);
        var entityVariable = Expression.Variable(typeof(object), "entity");
        Expression.Assign(entityVariable, callLoad);
        var lambda = Expression.Lambda>(
            entityVariable, lamdaParameterExpressions.ToArray());
        //compiles the Expression to a usable delegete.
        return lambda.Compile();
    }

In the mean time, I found the way to make it work:与此同时,我找到了让它工作的方法:



    private static Func GetDataExtractorForTypeWithId(Type type)
            {
                var paramId = Expression.Parameter(typeof(long), "id");
                ParameterExpression paramOptions = null;
                var facadetype = GetFacadeType(type.Name) ?? typeof(AzzFacade).MakeGenericType(type);
                MethodInfo loadMethod;
                var linkedEntitiesInterface = facadetype.GetInterface(typeof(IFacadeLoadLinkedEntities).Name);
                if (linkedEntitiesInterface != null)
                {
                    loadMethod = facadetype.GetMethod("LoadById");
                    paramOptions = Expression.Parameter(typeof(byte), "options");
                }
                else
                {
                    paramOptions = Expression.Parameter(typeof(byte));
                    loadMethod = facadetype.GetMethod("LoadByID", new Type[1]{typeof(long)});
                }
                var facadeConstructor = facadetype.GetConstructor(new Type[0]);
                if(facadeConstructor==null)
                    throw new NullReferenceException($"No parameterless constructor found for facade for type {type.Name}");
                MethodCallExpression callLoad;
                var newFacade = Expression.New(facadeConstructor);
                if (linkedEntitiesInterface != null)
                {
                    var conversionExpression = Expression.Convert(paramOptions, linkedEntitiesInterface.GetGenericArguments()[1]);
                    // ReSharper disable once AssignNullToNotNullAttribute
                    callLoad = Expression.Call(newFacade, loadMethod, paramId, conversionExpression);
                }
                else
                {
                    // ReSharper disable once AssignNullToNotNullAttribute
                    callLoad = Expression.Call(newFacade, loadMethod, paramId);
                }

                var lambda = Expression.Lambda>(
                    // ReSharper disable once AssignNullToNotNullAttribute
                    callLoad, paramId, paramOptions);
                //compiles the Expression to a usable delegate.
                return lambda.Compile();
            }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM