Как я могу передать различные функции выражения в перегруженных методах? - PullRequest
1 голос
/ 05 июля 2011

Мне нужен метод, подобный следующему:

// takes in a DefaultValue type as an Expression Function, with an argument
public void Register<T, TDefaultValueArgs>(Expression<Func<TDefaultValueArgs, T>> defaultValue)
{
    // stuff happens here.....
}

Я хотел бы добавить две перегруженные версии метода.Один, где defautlValue - это простой экземпляр T, а другой - где defaultValue - это функция выражения без параметра.

Я пришел к этому (непроверенному) решению:

// takes in a DefaultValue type
public void Register<T>(T defaultValue)
{
    // The statement below would be better, but isn't valid: "A lambda expression with a statement body cannot be converted to an expression tree"
    // Expression<Func<object, T>> defaultValueFunc = (o) => { return defaultValue; };

    Expression<Func<DefaultValueContainer<T>, T>> defaultValueFunc = (m => m.GetDefaultValue(defaultValue));
    Register<T, DefaultValueContainer<T>>(defaultValueFunc);
}

// takes in a DefaultValue type as an Expression Function
public void Register<T>(Expression<Func<T>> defaultValue)
{
    // The statement below would be better, but isn't valid: "A lambda expression with a statement body cannot be converted to an expression tree"
    // Expression<Func<object, T>> defaultValueFunc = (o) => { return defaultValue.Compile().Invoke(); };

    Expression<Func<DefaultValueContainer<T>, T>> defaultValueFunc = (m => m.GetDefaultValue(defaultValue));
    Register<T, DefaultValueContainer<T>>(defaultValueFunc);
}

private class DefaultValueContainer<T>
{
    public DefaultValueContainer()
    { }

    public T GetDefaultValue(T defaultValue)
    {
        return defaultValue;
    }

    public T GetDefaultValue(Expression<Func<T>> defaultValue)
    {
        return defaultValue.Compile().Invoke();
    }
}

IЗатем я предполагаю, что в моем исходном методе Regsiter<T, TDefaultValueArgs> я мог бы сделать что-то вроде этого:

T resolvedDefaultValue = default(T);

if (typeof(TDefaultValueArgs).Equals(typeof(DefaultValueContainer<T>)))
{
    var defaultValueContainer = Activator.CreateInstance<TDefaultValueArgs>();
    resolvedDefaultValue = defaultValue.Compile().Invoke(defaultValueContainer);
}

Все это, включая использование DefaultValueContainer<T>, кажется глупым.Должен быть лучший способ?

Примечание. По причинам, выходящим за рамки этого примера, я должен использовать тип выражения, а не только делегат.

1 Ответ

0 голосов
/ 05 июля 2011

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

То, что вы хотели в своем коде (но не работали):

Expression<Func<object, T>> defaultValueFunc =
                            (o) => { return defaultValue; };

Что вы должны иметь:

Expression<Func<object, T>> defaultValueFunc = 
                            (o) => defaultValue;

Аналогично, вместо:

Expression<Func<object, T>> defaultValueFunc =
                            (o) => { return defaultValue.Compile().Invoke(); };

Вы должны иметь:

Expression<Func<object, T>> defaultValueFunc =
                            (o) => defaultValue.Compile().Invoke();

Внесение этих изменений должно позволить вам использовать ваш оригинальный метод Register<T>.

Кроме того, я не уверен, является ли это просто ошибкой при написании вопроса, но вы можете выровнять параметры универсального типа в исходном методе, чтобы они были в том же порядке, что и Func <> параметры. Хотя это просто стилевое причуда.

...