【问题标题】:Expression inference during inheritance继承期间的表达式推断
【发布时间】:2010-09-20 16:12:04
【问题描述】:

我有以下代码:

using System;
using System.Linq;
using System.Linq.Expressions;

public class Program
{
    public static void Main()
    {
        Descendant d = new Descendant();
        d.TestMethod();
    }
}

public class Base
{
    protected void FigureItOut<TClass, TMember>(Expression<Func<TClass, TMember>> expr)
    {

    }
}

public class Descendant : Base
{
    public void TestMethod()
    {
        FigureItOut(c => c.Name);
    }

    public String Name { get; set; }
}

我收到此编译器错误消息:

The type arguments for method
'Base.FigureItOut<TClass,TMember> 
(System.Linq.Expressions.Expression<System.Func<TClass,TMember>>)'
cannot be inferred from the usage. Try specifying the type arguments explicitly.

如果我将对 FigureItOut 的调用更改为:

FigureItOut((Descendant c) => c.Name);

然后就可以了。有没有办法通过更改基类来编译第一个示例?

我知道如果我将整个 Base 类设为通用,如下所示:

public class Base<TDescendant>
{
    protected void FigureItOut<TMember>(Expression<Func<TDescendant, TMember>> expr)
    {

    }
}

public class Descendant : Base<Descendant>
{
    public void TestMethod()
    {
        FigureItOut(c => c.Name);
    }

    public String Name { get; set; }
}

然后它可以工作,但我宁愿不这样做,任何其他可以使用的技巧,也许是在方法级别(即以某种方式更改 FigureItOut)。

【问题讨论】:

  • 我添加了一个替代方案,避免了internal 要求(和扩展方法)

标签: c# compiler-errors expression-trees type-inference


【解决方案1】:

调用实际 (protected internal) 实现的扩展方法怎么样?唯一的缺点是您必须添加this.

这是因为source 参数(通过this)推断TClass 的类型。

public class Base
{
    protected internal void FigureItOut<TClass, TMember>(Expression<Func<TClass, TMember>> expr)
    {
        Debug.WriteLine("Got to actual method");
    }
}

public static class BaseExt
{
    public static void FigureItOut<TClass, TMember>(this TClass source, Expression<Func<TClass, TMember>> expr)
        where TClass : Base
    { // call the actual method
        Debug.WriteLine("Got to extension method");
        source.FigureItOut(expr);
    }
}
public class Descendant : Base
{
    public void TestMethod()
    {
        this.FigureItOut(c => c.Name);
    }

    public String Name { get; set; }
}

作为替代方案(如果 internal 很痛苦),请考虑将其设为静态,并使用主要用于类型推断的实例参数:

protected static void FigureItOut<TClass, TMember>(TClass source, Expression<Func<TClass, TMember>> expr)
{

}

public void TestMethod()
{
    FigureItOut(this, c => c.Name);
}

【讨论】:

  • 嗯,这解决了另一个问题,与一些菱形继承问题有关,但它也将 FigureItOut 方法暴露给了外人,我们将不得不考虑这是否是我们可以接受的权衡。
  • @lassevk - 好吧,内部的局外人...请注意,您也可以将 BaseExt 设为内部...
  • 问题是,并且知道我没有在问题中说明这一点,但是基类在类库中,而后代在另一个或应用程序项目中,所以还有一些这里的问题
  • @lassevk - 在这种情况下,只考虑 Base 上的受保护静态方法,它接受一个实例作为第一个参数,并使用 FigureItOut(this, c=>c.Name) - 几乎一样好。
【解决方案2】:

除非带参数,否则无法推断。 除非它分配返回值,否则无法推断。

【讨论】:

  • 不要忘记 arg0(又名“this”)也是一个可以驱动类型推断的参数,尤其是通过扩展方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-27
  • 2015-07-04
  • 1970-01-01
  • 1970-01-01
  • 2014-06-21
  • 1970-01-01
  • 2012-03-03
相关资源
最近更新 更多