简体   繁体   English

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

[英]Force C# compiler to use non-generic method overload with Linq Expression parameter

I have overloaded methods, one generic and one non-generic. 我有重载的方法,一种泛型和一种非泛型。 The two methods both receive a Linq Expression as single parameter: 这两种方法都将Linq表达式作为单个参数接收:

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

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

Now consider the following invocation: 现在考虑以下调用:

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

The compiler will pick the generic method since the Append() method does (unfortunately) return a StringBuilder . 因为Append()方法确实(不幸地)返回StringBuilder所以编译器将选择通用方法。 However, in my case I absolutely need the non-generic method to be called. 但是,就我而言,我绝对需要调用非泛型方法。

The following workaround shows that there is no type issue with the code (the non-generic call would be perfectly valid): 以下变通办法显示代码没有类型问题(非泛型调用将完全有效):

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

However, I'd prefer not to declare a variable with an explicit type and instead somehow get the compiler to pick the non-generic method (just like I could tell it to use the generic method with explicit type parameters). 但是,我宁愿不声明具有显式类型的变量,而是以某种方式使编译器选择非泛型方法(就像我可以告诉它使用具有显式类型参数的泛型方法一样)。

You can play with this at SharpLab.io . 您可以在SharpLab.io上玩这个游戏

This may seem like a workaround (because it is), but you can used a named parameter to clarify which method you are calling. 这似乎是一种解决方法(因为是这样),但是您可以使用命名参数来阐明您正在调用的方法。

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

When you want the non-generic version, just provide the parameter name action: in the argument list. 当您需要非通用版本时,只需在参数列表中提供参数名称action:

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

Output: 输出:

Test()
Test<T>()

This might be easier to use than writing out the expression cast. 这可能比写出表达式强制转换更容易使用。

Fiddle 小提琴

You can use an empty method to swallow the return value of sb.Append. 您可以使用空方法吞下sb.Append的返回值。 I wouldn't call this a workaround, since it just makes the compiler work normally, but it isn't totally clean and pretty either. 我不会将其称为解决方法,因为它只能使编译器正常工作,但也不是完全干净漂亮。

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

When you wrap the output in NoValue, the compiler correctly sees this as an Action, not a function. 当将输出包装为NoValue时,编译器正确地将其视为Action,而不是函数。

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

Output: 输出:

Test()
Test<T>()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM