Как установить параметр метода с помощью отражения - PullRequest
0 голосов
/ 19 марта 2012

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

Я пытаюсь найти способ передачи параметров в вызов метода - в этом примере я использую StartsWith параметр String и пытаюсь установить StringComparison.OrdinalIgnoreCase в качестве параметра.

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

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

Я использовал этот вопрос в качестве руководства, но решение здесь не применимо.

Вот код:

public static class LambdaExpressionHelper<T> {
    public static Expression<Func<T, bool>> Build(string propertyName, string method, string propertyValue) {
        PropertyInfo propertyInfo = typeof(T).GetProperty(propertyName);

        ParameterExpression e = Expression.Parameter(typeof(T), "e");
        MemberExpression m = Expression.MakeMemberAccess(e, propertyInfo);
        ConstantExpression c = Expression.Constant(propertyValue, m.Type);
        MethodInfo mi = m.Type.GetMethod(method, new Type[] { m.Type }, );

        // The below caused errors
        //object classInstance = Activator.CreateInstance(typeof(T), null);
        //object[] paramArray = new object[] { StringComparison.OrdinalIgnoreCase };
        //mi.Invoke(classInstance, paramArray);         

        Expression call = Expression.Call(m, mi, c);

        Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(call, e);
        return lambda;
    }
}

// External code:
var lambda = LambdaExpressionHelper<MailingListMember>.Build("EmailAddress", "StartsWith", "RoRy@");

Спасибо за любую помощь.

Ответы [ 2 ]

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

В общем случае это должно работать:

public static Expression<Func<T, bool>>
Build(string propertyName, string method, params object[] args) 
{
    var propertyInfo = typeof(T).GetProperty(propertyName);
    var e = Expression.Parameter(typeof(T), "e");
    var m = Expression.MakeMemberAccess(e, propertyInfo);

    var mi = m.Type.GetMethod(method, args.Select(a => a.GetType()).ToArray());
    var c = args.Select(a => Expression.Constant(a, a.GetType())).ToArray();

    Expression call = Expression.Call(m, mi, c);

    Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(call, e);
    return lambda;
}

Идея состоит в том, что вы принимаете любое количество константных аргументов и используете их типы для выбора соответствующей перегрузки при вызове GetMethod.После этого вы создаете соответствующее число константных выражений из этих аргументов для передачи в Expression.Call.

Таким образом, с помощью приведенного выше кода вы можете сделать:чтобы получить значение StringComparison.OrdinalIgnoreCase из строки "StringComparison.OrdinalIgnoreCase", я бы выделил это в отдельный метод, чтобы интерфейс Build мог оставаться универсальным.Как это сделать, описано в Получение значения Enum с помощью отражения (и я думаю, во многих подобных вопросах).

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

0 голосов
/ 19 марта 2012

Я не уверен, что точно понимаю ваш вопрос, но, надеюсь, это поможет вам в пути.

Если вы используете .NET 4.0, вы можете использовать новое ключевое слово "dynamic" для гораздо более простого отраженияcode:

dynamic myDynamicObj = "Hello World!"; // or Activator.CreateInstance...
var doesIndeed = myDynamicObj.StartsWith("Hello", StringComparison.OrdinalIgnoreCase);

Это действительно оценивает во время выполнения, поэтому убедитесь, что орфография / регистр и т. д. верны.

Редактировать: Предполагая, что вы всегда хотели вызывать методы с одним String-arg, возвращающим bool,Возможное решение - создать тип делегата -

delegate bool CompareString(String str);

, и второй аргумент Build будет иметь такой тип:

Build(String .., CompareString cs, String ...)

Но это не работает, если вам нужнодобавить дополнительные аргументы, как во втором аргументе типа StringComparison.Ответом может быть if / switch, то есть if (CompareString is StartsWith) ...

Извините, но не на компьютере с Windows, поэтому я не могу тестировать дальше.

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