Невозможно создать генератор с использованием выражений - PullRequest
1 голос
/ 19 июня 2020

Что у меня есть:

public class HubGroup: HubObject
{
    public HubGroup(elnGroup group)
    {//do stuff}
}

public class elnGroup: elnObject
{
    //has properties
}

Мое требование - когда я даю 2 типа методу, он сгенерирует функцию, которая примет объект elnGroup в качестве параметра и вернет новый экземпляр HubGroup. Я много чего пробовал, но не смог найти способ сделать это быстро (эти функции генератора будут запускаться несколько раз)

Я знаю, что вы скажете использовать дженерики, но мои типы генерируются во время выполнения . Все, что у меня есть, - это базовые классы для обоих типов, которые я могу явно объявить. Код, который вы видите ниже, - это кусочки, которые у меня есть, просто чтобы вы знали, что у меня происходит.

Я называю это так:

public class ApiDataHandler
{
    //this will be called by a method to give json content for objEln
    public void SoFunny<T>(string strContent, T objHub) where T : HubObject
    {
        if (typeof(T) == typeof(HubGroup))
        {
            if (string.IsNullOrEmpty(strContant))
            {
                throw new Exception("Cannot parse null/empty string! ---ApiDataHandler---");
            }

            var objEln = JsonConvert.DeserializeObject<elnGroup>(strContant);
            GetHubObjectGenerator(objEln.GetType(), objHub.GetType());
        }
    }
}

Что я хочу создать:

Func<object,object> generator = (input) => {var bObj = input as BObject;
                                            var aObj = new AObject(bObj);
                                            return aObj;
                                            }

Я сделал это: но он продолжает говорить:

InvalidOperationException: переменная 'objEln' типа 'ElnHub.HubObjectModel.elnGroup' указана из области '', но это не определено

//also inside ApiData Handler class
    public Func<object, object> GetHubObjectGenerator(Type elnObjectType, Type hubObjectType)
    {
        ParameterExpression inputParam = Expression.Parameter(typeof(object), "input");
        ParameterExpression objCastedAsEln = Expression.Parameter(elnObjectType, "objEln");
        ParameterExpression objHub = Expression.Parameter(hubObjectType, "objHub");
        var cast = Expression.TypeAs(inputParam, elnObjectType);
        var assignCast = Expression.Assign(objCastedAsEln, cast);
        var constructor = hubObjectType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { elnObjectType }, null);
        var callingConstructor = Expression.New(constructor, new[] { objCastedAsEln });
        var assignNewObj = Expression.Assign(objHub, callingConstructor);
        var bodyBlock = Expression.Block(new[] { inputParam },
                assignCast,
                assignNewObj,
                objHub
            );
        var l = Expression.Lambda<Func<object, object>>(
                bodyBlock,
                inputParam
            );

        Func<object, object> HubObjectGenerator = l.Compile();

        return HubObjectGenerator;
    }

Я также пробовал это, где я отправляю общие типы c, но не смог найти свой путь. Немного потеряно здесь:

    public Func<T,T1> GetHubObjectGenerator<T,T1>() where T : elnObject where T1 : HubObject
    {
        ParameterExpression argParam = Expression.Parameter(typeof(T), "objEln");
        var constructor = typeof(T1).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance,null,new[] { typeof(T) },null);
        Func<T, T1> HubObjectGenerator = Expression.Lambda<Func<T, T1>>(
                Expression.New(constructor, new[] { argParam, }),
                argParam
            ).Compile();

        return HubObjectGenerator;
    }

1 Ответ

1 голос
/ 19 июня 2020

Вы хотите написать что-то вроде:

Func<object,object> generator = (input) =>
{
    return new AObject((BObject)input);
}

Вам нужно что-то вроде:

public Func<object, object> GetHubObjectGenerator(Type elnObjectType, Type hubObjectType)
{
    var inputParameter = ExpressionParameter(typeof(object), "input");
    var castInput = Expression.Convert(inputParameter, elnObjectType);
    var constructor = hubObjectType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { elnObjectType }, null);
    var instantiation = Expression.New(constructor, castInput);
    var lambda = Expression.Lambda<Func<object, object>>(instantiation, inputParameter);
    return lambda.Compile();
}

Здесь вы также можете легко использовать дженерики, вам даже не нужно приведение:

public Func<THub, TEln> GetHubObjectGenerator<THub, TEln>() where THub : HubObject, TEln : elnObject
{
    var inputParameter = ExpressionParameter(typeof(TEln), "input");
    var constructor = typeof(THub).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(TEln) }, null);
    var instantiation = Expression.New(constructor, inputParameter);
    var lambda = Expression.Lambda<Func<THub, TEln>>(instantiation, inputParameter);
    return lambda.Compile();
}

Я не использовал здесь переменные или Expression.Block, так как в этом нет необходимости. Если вы действительно хотите создать промежуточные переменные, используйте Expression.Variable (Expression.Parameter только для входных параметров). Что-то вроде:

public Func<object, object> GetHubObjectGenerator(Type elnObjectType, Type hubObjectType)
{
    var inputParameter = ExpressionParameter(typeof(object), "input");

    var castInputVar = Expression.Variable(elnObjectType, "eln");
    var castInput = Expression.Convert(inputParameter, elnObjectType);
    var castInputAssign = Expression.Assign(castInputVar, castInput);

    var constructor = hubObjectType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { elnObjectType }, null);
    var hubObjectVar = Expression.Variable(hubObjectType, "hub");
    var instantiation = Expression.New(constructor, castInputVar);
    var hubObjectAssign = Expression.Assign(hubObjectVar, instantiation);

    var block = Expression.Block(new[] { castInputVar, hubObjectVar },
        castInputAssign,
        hubObjectAssign,
        hubObject);

    var lambda = Expression.Lambda<Func<object, object>>(block, inputParameter);
    return lambda.Compile();
}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...