2010-09-02 80 views
13

我試圖創建一個通用的擴展方法,即在輸入數據表的工作原理:通用擴展方法:類型參數不能從使用推斷

public static class Extensions 
{ 
    public static TableType DoSomething<TableType, RowType>(this TableType table, param Expression<Func<RowType, bool>>[] predicates) 
     where TableType : TypedTableBase<RowType> 
     where RowType : DataRow 
    { 
     // do something to each row of the table where the row matches the predicates 
     return table; 
    } 

    [STAThread] 
    public static void main() 
    { 
     MyTypedDataSet.MyTypedDataTable table = getDefaultTable(); 
    } 

    public static MyTypedDataSet.MyTypedDataTable getDefaultTable() 
    { 
     // this line compiles fine and does what I want: 
     return new MyTypedDataSet.MyTypedDataTable().DoSomething<MyTypedDataSet.MyTypedDataTable, MyTypedDataSet.MyTypedRow>(row => row.Field1 == "foo"); 

     // this line doesn't compile : 
     return new MyTypedDataSet.MyTypedDataTable().DoSomething(row => row.Field1 == "foo"); 
     // Error : The type arguments .. cannot be inferred from the usage 
    } 
} 

第一線工作正常,但它真的很醜陋...
第二行不編譯,因爲編譯器無法推斷出RowType類型的類型。
這是一種將被許多不同程序員用作DataLayer的一部分的方法,所以我寧願不需要它們來指定TypeParameter。
編譯器不應該知道RowType與TypedTableBase使用的類型相同嗎?

由於在此代碼示例中可能不明顯的不同原因,我確實需要以其原始形式返回數據表。而我需要的原因RowType是這樣的'Expression < Func < T,bool>>'將被鍵入並且被InteliSence看到。

感謝

回答

19

方法類型推斷不會使從參數推論約束。它從參數推斷到形式參數,然後檢查從形式參數中得出的推論是否滿足約束條件。

你的情況不存在從參數足夠的數據來推斷類型參數是什麼,而不首先看的限制,這我們不打算這樣做直到我們檢查推論反對限制。對此很抱歉,但這是指定類型推斷算法的方式。

我已經被問過這麼多次的問題,而且我的共識似乎是道德上錯誤的,因爲我堅持認爲推理應該從論據中僅依據形式參數來推論。有關十幾人告訴我,我判斷錯誤在這方面,看到了評論我的這個密切相關的問題的分析:

http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx

我堅持我的立場。

+3

我很害怕那個......謝謝你的回答 – 2010-09-02 19:14:59

+1

你是對的:) – Brian 2010-09-02 21:43:38

0

埃裏克的答案很好解釋爲什麼不能推斷類型。以下是一些建議,希望能夠減少您必須編寫的代碼的詳細程度。

如果您可以明確定義lambda表達式的類型,那麼它可以推斷出類型。

如何做到這一點的一個例子如下。我創建了一個明確爲Expression<Func<MyTypedDataSet.MyTypedRow, bool>>類型的criteria參數。在這個例子中,這並不能爲你節省很多輸入,但實際上你可以利用這個。

 MyTypedDataSet.MyTypedDataTable table = new MyTypedDataSet.MyTypedDataTable(); 

     Expression<Func<MyTypedDataSet.MyTypedRow, bool>> criteria = row => row.Field1 == "foo"; 

     return table.DoSomething(criteria); 

編輯:改變了我的例子使用其他擴展方法,而不是從System.Data.TypedTableBase<T>派生自定義TypedTableBase<T>類。

下面是另一個可以更好地推斷類型參數的例子。您可以定義另一個擴展方法(我的名字叫RowPredicate),它只有一個類型參數來推斷。第一個參數是TypedTableBase<RowType>型的,所以編譯器應該沒有問題,推斷從類型:

public static Expression<Func<RowType, bool>> RowPredicate<RowType>(this TypedTableBase<RowType> table, Expression<Func<RowType, bool>> predicate) 
     where RowType : DataRow 
    { 
     return predicate; 
    } 

這可以讓你編譯下面的代碼:

 MyTypedDataSet.MyTypedDataTable table = new MyTypedDataSet.MyTypedDataTable(); 

     return table.DoSomething(table.RowPredicate(row => row.Field1 == "foo")); 

主要是table參數只是服務器通知編譯器使用的類型爲RowType。這是一個好主意嗎?我不太確定,但它確實允許編譯器推斷所有的泛型類型。

0

即使這是不理想,我放棄了試圖在所有的巫婆返回任何東西可以讓我做這樣的事情:

public static void DoSomething<RowType>(this TypedTableBase<RowType> table, param Expression<Func<RowType, bool>>[] predicates) 
    where RowType : DataRow 
    { 
     // do something to each row of the table where the row matches the predicates 
     // do not return the table... too bad for chaining commands 
    } 

,然後用它像這樣:

MyTypedDataSet.MyTypedDataTable table = new MyTypedDataSet.MyTypedDataTable(); 
table.DoSomething(row => row.Field1 == "foo")); 

和編譯器推斷正確的類型...

謝謝你們的答案。

相關問題