强制 C# 编译器对 Linq 表达式参数使用非泛型方法重载



我有重载的方法,一个泛型的,一个非泛型的。这两种方法都接收 Linq 表达式作为单个参数:

public void Test(Expression<Action<char>> expr) {}
public void Test<T>(Expression<Func<char, T>> expr) {}

现在考虑以下调用:

var sb = new StringBuilder();
Test(c => sb.Append(c));

编译器将选择泛型方法,因为Append()方法(不幸的是)确实返回StringBuilder。但是,就我而言,我绝对需要调用非泛型方法。

以下解决方法表明代码没有类型问题(非泛型调用将完全有效):

Expression<Action<char>> expr = c => sb.Append(c);
Test(expr);

但是,我不想声明具有显式类型的变量,而是以某种方式让编译器选择非泛型方法(就像我可以告诉它使用带有显式类型参数的泛型方法一样)。

你可以在 SharpLab.io 玩这个。

这似乎是一种解决方法(因为它是),但您可以使用命名参数来阐明要调用的方法。

static public void Test(Expression<Action<char>> action) 
{
    Console.WriteLine("Test()");
}
static public void Test<T>(Expression<Func<char, T>> func) 
{
    Console.WriteLine("Test<T>()");
}

如果需要非通用版本,只需在参数列表中提供参数名称action:

static public void Main()
{
    var sb = new StringBuilder();
    Test(action: c => sb.Append(c) );
    Test(func: c => sb.Append(c) );
}

输出:

Test()
Test<T>()

这可能比写出表达式强制转换更容易使用。

小提琴

可以使用空方法吞下 sb 的返回值。附加。 我不会称其为解决方法,因为它只是使编译器正常工作,但它也不是完全干净和漂亮的。

static public void NoValue(object value) {}
static public void Test(Expression<Action<char>> action) 
{
    Console.WriteLine("Test()");
}
static public void Test<T>(Expression<Func<char, T>> func) 
{
    Console.WriteLine("Test<T>()");
}

将输出包装在 NoValue 中时,编译器会正确地将其视为操作,而不是函数。

static public void Main()
{
    var sb = new StringBuilder();
    Test(c => NoValue(sb.Append(c)) );
    Test(c => sb.Append(c) );
}

输出:

Test()
Test<T>()

最新更新