Выражения LINQ Создание массива с различными типами объектов - PullRequest
1 голос
/ 11 марта 2012

Я делаю какой-то анализ пользовательского ввода, и здесь мне нужно проанализировать массив аргументов, которые должны быть определенного типа.

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

NewArrayExpression returnValue = Expression.NewArrayInit(typeof(object), expressionList);

я получаю следующее исключение: выражение типа 'System.Int32' не может использоваться для инициализации массива типа 'System.Object'.

То есть, я полагаю, потому что никакого неявного бокса не происходит.Так что я сам его запакую:

expressionList.Add(Expression.TypeAs(expression, typeof(object))); or
expressionList.Add(Expression.Convert(expression, typeof(object)));

Пока все хорошо: у меня есть список объектов различных типов в массиве.

Но, когда я наконец получаю нужный тип, я пытаюсьпреобразуя все значения из верхнего массива в этот тип (допустим, этот тип обычно int), я конвертирую его:

Expression.Convert(expr, typeof(int)); or
Expression.Unbox(expr, typeof(int));

Это отладочный вид обеих команд, когда expr действительно является строкой "aaaaa":

(System.Int32)((System.Object)"aaaaa")

Теперь моя проблема: это НЕ БУДЕТ генерировать исключение.Но это произойдет, когда выражение будет окончательно скомпилировано.Я имею в виду, строка не является int.

Может быть, это действительно не должно вызывать исключения, я не знаю.Но это не работает для меня.

Есть ли лекарство от этого?

РЕДАКТИРОВАТЬ: Код выглядит следующим образом:

static Expression InArguments(ParameterExpression pe, string[] arguments)
{
    List<Expression> listaExpr = new List<Expression>();
    foreach (string s in arguments)
    {
        Expression expression = Complete(pe, s); // evaluate argument
        // listaExpr.Add(Expression.Convert(expression, typeof(object)));
    }
    return Expression.NewArrayInit(typeof(object), listaExpr);
}

Ответы [ 2 ]

2 голосов
/ 12 марта 2012

Мне кажется, что вы знаете тип, просто вы вычисляете его слишком поздно.Если бы вы могли изменить это, это решило бы вашу проблему.Метод будет выглядеть следующим образом:

static Expression InArguments(
    ParameterExpression pe, string[] arguments, Type itemType)
{
    List<Expression> listaExpr = new List<Expression>();
    foreach (string s in arguments)
    {
        Expression expression = Complete(pe, s, itemType); // evaluate argument
        listaExpr.Add(expression, typeof(object));
    }
    return Expression.NewArrayInit(itemType, listaExpr);
}

И код, который его вызывает, может выглядеть примерно так:

Expression inProperty = InProperty(…);
Expression inArguments = InArguments(pe, arguments, inProperty.Type);

Expression result = Expression.Call(containsMethod, inArguments, inProperty);
0 голосов
/ 12 марта 2012

@ svick

Да, это была моя проблема.Вся моя система была настроена так, чтобы разрешать левый и правый операнды независимо, а затем проверять конвертируемость между ними.Итак, я хотел, чтобы мой правый операнд оператора IN возвращал выражение массива объектов, чтобы я мог проверить каждый из объектов на конвертируемость, но мне кажется, что, как только я конвертирую их в объект, они конвертируются во что угодно ???,

Итак, я решил вернуть следующее выражение из моего правого операнда:

    static Expression InArguments(ParameterExpression pe, string arguments)
    {
        string substr = arguments.Substring(1, arguments.Length - 2);
        string[] arr = substr.Split(',');
        return Expression.Constant(arr, typeof(string[]));
    }

А потом:

    static Expression InOperator(Expression left, Expression right, ParameterExpression pe)
    {
        Expression finalexpr = null;

        // this solved my problem.
        string[] args = Expression.Lambda<Func<string[]>>(right).Compile()();

        foreach (string s in args)
        {
            Expression converted = null;                

            try
            {
                Expression expr = Complete(pe, s);
                converted = Expression.Convert(expr, (left as Expression).Type);
            }
            catch
            {
                throw;
            }

            if (finalexpr == null) finalexpr = Expression.Constant(false);
            finalexpr = Expression.OrElse(finalexpr, Expression.Equal(left, converted));
        }

        return finalexpr;
    }

Я переправил свои аргументы в точку, гдена самом деле я могу сослаться на левый тип операнда внутри константного выражения string [], а затем скомпилировать его, чтобы получить мои строковые аргументы обратно.

Но все же мне бы понравилось, если бы я мог переслать его в объектемассив ...

...