2011-05-03 158 views
11

我有2层重载C#的功能是这样的:使用OleCommand和其他的SqlCommand为函数的返回值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) 

基本上之一。

但是关于这个丑陋的事情是,我必须给函数指针转换为正确的类型,即使我觉得编译器应该能够解决它没有问题:

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

_Insert(enquiry, "Enquiry", (Func<string, object[], SqlCommand>)(_RemoteDatabase.GetCommand)); 

有什么办法告诉编译器变得更聪明以至于我不必进行类型转换?还是我做错了什么?

编辑: 增加了一个赏金,因为我真的有兴趣学习。感谢您的任何建议。

+0

哇..所有的答案各有4票!我该如何决定? – Jake 2011-07-15 03:45:29

+0

C#4.0也可以计算出“动态”场景,但是会有性能问题。 – 2011-07-18 09:09:36

回答

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

编辑 - 我发现这个post by Eric Lippert that answers this question

一个有趣事实上:lambdas的转换规则确实采用了 帐户返回类型。如果你说Foo(()=> X())那么我们做 的事情。 lambdas和方法组具有不同的可兑换规则的事实是相当不幸的。

+0

不错的链接。它很好地回答了这个有趣的事实 – saus 2011-07-14 04:21:12

+0

。谢谢=) – Jake 2011-07-15 04:33:06

+0

@BrandonAGr我如何奖励赏金?是否将其标为足够回答? – Jake 2011-07-21 15:04:12

4

您能使用Func<string, object[], DbCommand>吗?这也可以让你摆脱过载,只需要一个功能。

+0

我重新访问了我的旧项目,发现根据我的(有限)知识,这可能是不可能的。实质上,每个_Insert在传递给Func()之前的数据处理过程中都是不同的。在这种情况下,我甚至在执行Func()之前不能(不知道如何)测试返回类型。 – Jake 2011-07-15 03:56:40

7

编辑:这是通过在C#规范的第Overload resolution定义的过程引起的。一旦获得可用的候选功能成员集合,它就不能选择“最佳功能”,因为它在重载解析期间不会在帐户中获得返回类型。由于它不能根据规范选择最佳功能模糊方法调用错误发生。

但是,如果你的目标是简化方法的调用,并避免长时间铸造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"); 
    } 

通知简化方法调用

_Insert(new Hashtable(), "OleTable", F1); 
_Insert(new Hashtable(), "OleTable", F2); 

是编译就好

+0

完全正确,希望您满意我的最新编辑 – 2011-07-14 05:54:16

+0

+1 ...让你为它工作虽然;) – saus 2011-07-14 06:00:05

+0

@Valentin这可能只是回答了我对Joel =的评论=) – Jake 2011-07-15 04:32:29

1

很好,因为返回值确实没有考虑到,怎么样的其中之一:(注:我写的一个代码略有不同的测试项目,所以可能会有一些问题,但这应该给出这个想法...)

public class RemoteDatabase 
{  
     // changed to private, referenced by CommandWay1 
     private SqlCommand GetCommand(string query, object[] values) 
     { 
      /* GetCommand() code */ 
     } 

     public Func<string, object[], SqlCommand> CommandWay1 
     { 
      get 
      { 
      return (q,v) => GetCommand(q,v); 
      } 
     } 

     // or, you could remove the above and just have this, 
     // with the code directly in the property 
     public Func<string, object[], SqlCommand> CommandWay2 
     { 
      get 
      { 
      return 
       (q,v) => 
       { 
        /* GetCommand() code */ 
       }; 
     } 
} 

的话,我是能够得到每个这些没有铸造编译:

_Insert(enquiry, "Enquiry", (q,v) => _RemoteDatabase.GetCommand(q,v)); 
_Insert(enquiry, "Enquiry", _RemoteDatabase.CommandWay1); 
_Insert(enquiry, "Enquiry", _RemoteDatabase.CommandWay2); 
+0

是的,它像一个魅力。已经从Brandon的Overloaded()中获得了这个想法。感谢细节。 – Jake 2011-07-15 04:34:27