2011-05-03 189 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