重载函数中的C#函数指针

Jak*_*ake 11 c# overloading

我有2个重载的C#函数,如下所示:

private void _Insert(Hashtable hash, string tablename, Func<string, object[], SqlCommand> command)
private void _Insert(Hashtable hash, string tablename, Func<string, object[], OleCommand> command)
Run Code Online (Sandbox Code Playgroud)

基本上一个使用OleCommand和另一个SqlCommand作为函数的返回值.

但是关于这一点的丑陋之处在于我必须将函数指针强制转换为正确的类型,即使我觉得编译器应该能够解决它而没有问题:

class RemoteDatabase
{    
      public SqlCommand GetCommand(string query, object[] values);
}

_Insert(enquiry, "Enquiry", (Func<string, object[], SqlCommand>)(_RemoteDatabase.GetCommand));
Run Code Online (Sandbox Code Playgroud)

有没有办法告诉编译器更聪明,以便我不必进行类型转换?或者我做错了什么?

编辑:增加了赏金,因为我真的很有兴趣学习.谢谢你的建议.

Bra*_*AGr 8

虽然没有直接回答你的问题,但我在编写测试用例时遇到了以下问题,你可以通过将调用包装在另一个lambda中来编译它.其中以另一个方法调用为代价删除了显式强制转换(至少我是这么认为的,还没看过IL)

class RemoteDatabase
{
    public int GetCommand(){return 5;}
}

class Program
{

    static void Main(string[] args)
    {
        var rd = new RemoteDatabase();

        // Overloaded(1, rd.GetCommand); // this is a compile error, ambigous

        Overloaded(1, () => rd.GetCommand()); // this compiles and works

        Console.ReadLine();
    }

    static void Overloaded(int paramOne, Func<int> paramFun)
    {
        Console.WriteLine("First {0} {1}", paramOne, paramFun());
    }

    static void Overloaded(int paramOne, Func<string> paramFun)
    {
        Console.WriteLine("Second {0} {1}", paramOne, paramFun());
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑 - 我发现Eric Lippert的这篇文章回答了这个问题

一个有趣的事实:lambda的转换规则确实考虑了返回类型.如果你说Foo(()=> X())那么我们做对了.lambdas和方法组具有不同的可兑换规则这一事实是相当不幸的.


Val*_*zub 7

编辑:这是由C#规范的重载解析部分中定义的进程引起的.一旦获得适用的候选函数成员集,它就无法选择"最佳函数",因为它在重载解析期间不会在帐户中采用返回类型.由于无法选择最佳功能,因此根据规范发生呼叫错误.

但是,如果您的目标是简化方法调用并避免长时间转换为func,则可以使用泛型并使_Insert方法复杂化,例如:

public  void Main()
    {
        _Insert(new Hashtable(), "SqlTable", F1);
        _Insert(new Hashtable(), "OleTable", F2);
    }

    private static SqlCommand F1(string name, object[] array)
    {
        return new SqlCommand();
    }

    private static OleDbCommand F2(string name, object[] array)
    {
        return new OleDbCommand();
    }

    private void _Insert<T>(Hashtable hash, string tablename, Func<string, object[], T> command) 
    {
        if (typeof(T) == typeof(SqlCommand)) {
            SqlCommand result = command(null, null) as SqlCommand;
        }
        else if (typeof(T) == typeof(OleDbCommand)) {
            OleDbCommand result = command(null, null) as OleDbCommand;
        }
        else throw new ArgumentOutOfRangeException("command");
    }
Run Code Online (Sandbox Code Playgroud)

注意简化的方法调用

_Insert(new Hashtable(), "OleTable", F1);
_Insert(new Hashtable(), "OleTable", F2);
Run Code Online (Sandbox Code Playgroud)

编译得很好