如何在重载方法中传递各种表达式函数?

时间:2011-07-05 00:47:27

标签: c# delegates lambda expression-trees

我需要一种类似的方法:

// 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();
    }
}

我接着假设,在我原来的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 :(得分:0)

您可以将lambdas更改为表达式lambda,而无需使用包装类。

你想要的代码(但没有用):

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&lt;&gt;的顺序相同;参数。但是,这只是一种风格狡辩。