Как распознать Lambda MemberExpression типа «ссылка на поле» - PullRequest
1 голос
/ 09 июля 2011

Мне пришлось найти способ замены неявных ссылок на поля в лямбда-выражении его действительным значением. Например:

Expression<Func<TestObject, String>> exp = null;
for (int i = 0; i < 1; i++)
{
    exp = t => t.SubObjs[i].TestSTR;
}
Func<TestObject, String> testFunc = exp.Compile();
String testValue = testFunc(myObj);

Осматривая делегата, вы можете увидеть это:

{t => t.SubObjs.get_Item(value(testExpression.Program+<>c__DisplayClass4).i).TestSTR}

При вызове делегата вне цикла for значение «i» определяется по ссылке. Но «i» изменилось с момента последней итерации («i» == 1, а не 0).

Итак, я строю определенный ExpressionVisitor, чтобы заменить соответствующий узел на ConstantExpression:

public class ExpressionParameterSolver : ExpressionVisitor
{
    protected override Expression VisitMember(MemberExpression node)
    {
        if (node.ToString().StartsWith("value(") && node.NodeType == ExpressionType.MemberAccess)
        {
            var index = Expression.Lambda(node).Compile().DynamicInvoke(null);
            return Expression.Constant(index, index.GetType());
        }
        return base.VisitMember(node);
    }
}

Я не нашел другого способа, кроме .StartsWith ("value ("), чтобы определить, что текущий узел является ссылкой на поле ... этот тип узла наследуется от FieldExpression, но этот класс является внутренним и я не уверен, что FieldExpression инкапсулирует только то, что я считаю «неявной ссылкой на поле».

Так есть ли способ (атрибут или метод) явно знать, что узел MemberExpression является неявной ссылкой на поле ???

Заранее спасибо !!!

и благодаря этой записи 1020 *

1 Ответ

4 голосов
/ 09 июля 2011

Просто извлеките свойство Member из выражения и посмотрите, является ли оно FieldInfo ...

Если вы хотите, чтобы оно было только для случаев, когда класс является компилятором-произведенный вы можете использовать

if (expression.Member is FieldInfo && 
    expression.Member
              .DeclaringType
              .IsDefined(typeof(CompilerGeneratedAttribute), false))
{
    ....
}

Могут быть и другие причины, по которым тип может быть сгенерирован компилятором.Для меня это не очень хорошая идея.

Разве вы не можете просто избежать захвата переменных цикла в своих лямбда-выражениях для начала?

...