代码之家  ›  专栏  ›  技术社区  ›  Lucero

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

  •  0
  • Lucero  · 技术社区  · 7 年前

    我有重载方法,一个是泛型的,一个是非泛型的。这两种方法都将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

    2 回复  |  直到 7 年前
        1
  •  3
  •   John Wu    7 年前

    这看起来像是一种解决方法(因为它是),但您可以使用命名参数来澄清您正在调用的方法。

    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>()
    

    这可能比写出表达式cast更容易使用。

    Fiddle

        2
  •  1
  •   Grax32    7 年前

    您可以使用一个空方法来接受sb.Append的返回值。我不认为这是一种变通方法,因为它只是使编译器正常工作,但它也不是完全干净和漂亮的。

    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>()