2011-09-27 70 views
18

由於Javascript是我最熟練的語言,因此我熟悉使用函數作爲第一類對象。我曾以爲C#缺乏這個功能,但後來我聽說FuncActiondelegate,我認爲這是非常棒的。爲什麼Funcs不能接受超過16個參數?

例如,你可以聲明一個Func連接兩個字符串,並把這樣它們之間的空間:

Func<string, string, string> concat = (a,b) => a + " " + b; 

我注意到,當你鍵入

Func< 

的智能感知表明,有17個過載:

delegate System.Func<out TResult> 
delegate System.Func<in T, out TResult> 
delegate System.Func<in T1, in T2, out TResult> 
...snip... 
delegate System.Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, out TResult> 

這讓我發笑。我看着MSDN docsFunc又笑了起來。這讓我試圖用17個參數聲明Func。它會導致錯誤(Using the generic type 'System.Func<TResult>' requires 1 type arguments)。

我同意,這可能不是一個好主意,有一個Func接受超過16個參數。即使如此,這似乎是Func被執行的一種方式。它需要17個不同的重載記錄。這就是它真正需要知道的一切:最後一個類型參數是返回類型,並且它之前的所有類型參數都是參數類型。

所以我能做什麼,如果我想創造超過16個參數的Func?爲什麼有一個限制呢?爲什麼C#不能讓你用任意數量的參數聲明Func

+0

我可以想象,因爲如果你試圖用'params'返回類型將被解釋爲一個參數的類型。但是,我永遠無法理解爲什麼它不能是'Func鍵<出來回報,...>'(因爲你用聲明原型的函數(有返回類型),那麼參數(例如'無效美孚(A,B,C)' )) –

+3

這只是一個簡單的聲明。 .NET設計師在16之後感到厭倦。如果您不僅僅需要聲明自己的Func <>, –

+0

@HansPassant的一點是,爲什麼他們甚至有繼續增加的過載,直到他們看累了吧?爲什麼他們不能只有一種更一般的方式來處理它,只需要一個'out TResult'和'in T'0或更多次? –

回答

16

你希望這樣的事情variadic type arguments其中C#所缺乏的。 C#要求固定類屬的類型,因此可以擴大FuncActionTuple類型。

如果你的語言購物,加入這個功能在C++ 11,但你應該只使用jQuery。 :-)

+0

我很想知道你將如何製作「Tuple」的可變化版本! – Gabe

+0

@Gabe:查看我爲C++語法鏈接的維基百科文章。我可以在C#中想象這樣的事情:'class Foo {}'(接受一個數組類型)。 – Daniel

+0

@Gabe:即使C#獲得可變參數模板,它也只是缺少優化設施。它不會內聯將類作爲參數的函數,因此當您嘗試構造一個具有16個參數的元組時,您將獲得32個函數調用,而C++將內聯函數調用爲0個函數調用。 – Dani

0

Why is there a limit anyway?

有起作用的可能不應該有超過3個參數的意見。如果它有更多,它變得越來越難以理解。當然,這可能不是C#中這種方式的原因,但這個限制畢竟不是什麼壞事。

我認爲,即使16的這個限制是太多,而且已經鼓勵糟糕的設計選擇。

14

您可以定義您需要的任何代表。因此,與20個參數的Func將被定義是這樣的:

public delegate R Func< 
    P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, 
    P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, R>(
     P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, 
     P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, 
     P10 p10, P11 p11, P12 p12, P13 p13, P14 p14, 
     P15 p15, P16 p16, P17 p17, P18 p18, P19 p19); 

然後,您可以使用這樣的:

Func< 
     int, int, int, int, int, int, int, int, int, int, 
     int, int, int, int, int, int, int, int, int, int, int> f = (
      p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, 
      p11, p12, p13, p14, p15, p16, p17, p18, p19) => 
       p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10 
        + p11 + p12 + p13 + p14 + p15 + p16 + p17 + p18 + p19; 

var r = f(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); 

C#也可以讓你在任何委託使用lambda語法,所以你也可以這樣做這樣的:

public delegate R ArrayFunc<P, R>(params P[] parameters); 

,然後用它像這樣:

ArrayFunc<int, int> af = ps => ps.Sum(); 

var ar = af(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); 

這是語言的一個非常靈活和強大的功能。

+0

我認爲OP首先想知道爲什麼需要這些變體。告訴他,你可以進一步擴散他們並沒有解決這個問題。 – Daniel

+3

@Daniel - OP詢問他如何創建一個具有多於16個參數的委託,並且爲什麼他不能聲明具有可變數量參數的委託。我已經向他展示瞭如何做到這兩點。除此之外,除了任意選擇外,沒有任何理由說明爲什麼框架停在16位。在.NET 2.0中,'Func'只有四個參數。 – Enigmativity

5

我想我明白 - 你可以用JavaScript和功能(參數)做的是preaty整潔,但它也並非靜態類型。

但請注意,您再也不需要在函數式編程多個參數反正。你可以鏈儘可能多的說法是你通過返回另一個功能(這是FP一個共同的特點,並與curring在JS也繳費,但只有與彎曲系統有點技術heavaly使用)喜歡。

當然這是ackward在C#:

Func<A1,Func<A2,Func<A3,...<Func<An,Result>>...> 
    x1 => 
    (x2 => 
     (x3 => 
     ... 
      (xn => 
       { /*return soomething */ } 
))...); 

,但是這是F#是;),當然你得做出這個功能與以上幾個參數的更多(低於16路)無論如何! 。

+2

我同意:_「這是F#的用途」_ – Daniel

1

System.Func代表很可能有感謝BCL團隊..誰實現包括有限數量的預定義通用的代表將方便(甚至需要很多的情況下)。

要做你說的話,即一個Func委託的無限數量的通用參數需要一個語言改變..責任可能在於c#和vb.net團隊(以及其他人)可能會改變語言允許這個。

也許,在某種程度上,如果這個功能的好處超過了預先定義的少數Func代表的成本,並且這比其他語言更改更重要(並且它不是一個突破性更改),相關團隊我實現無限通用參數..雖然可能不會有一段時間!

相關問題