【问题标题】:How can I pass various Expression Functions in overloaded methods?如何在重载方法中传递各种表达式函数?
【发布时间】:2011-07-05 00:47:26
【问题描述】:

我需要类似这样的方法:

// 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&lt;T, TDefaultValueArgs&gt; 方法中,我可以做这样的事情:

T resolvedDefaultValue = default(T);

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

所有这一切,包括DefaultValueContainer&lt;T&gt; 的使用,似乎都很愚蠢。一定有更好的办法吗?

注意:由于本示例范围之外的原因,我需要使用表达式类型,而不仅仅是委托。

【问题讨论】:

    标签: c# delegates lambda expression-trees


    【解决方案1】:

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

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

    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&lt;T&gt; 方法。

    另外,我不确定这是否只是编写问题时的错误,但您可能希望在原始方法中对齐泛型类型参数,以便它们与 Func 的顺序相同参数。不过,这只是一种风格上的狡辩。

    【讨论】:

      猜你喜欢
      • 2023-03-17
      • 1970-01-01
      • 1970-01-01
      • 2011-06-30
      • 1970-01-01
      • 2014-01-23
      • 2019-12-13
      • 2022-01-24
      • 1970-01-01
      相关资源
      最近更新 更多