2015-05-03 15 views
-1

如果我們想要單個IEnumerable<T>表示兩個IEnumberable<T>的連接,我們可以使用LINQ Concat()方法。LINQ與單個額外元素的連接

例如:

int[] a = new int[] { 1, 2, 3 }; 
int[] b = new int[] { 4, 5 }; 

foreach (int i in a.Concat(b)) 
{ 
    Console.Write(i); 
} 

當然輸出12345的。

我的問題是,爲什麼沒有的Concat()超載只接受一個類型的單個元素T使得:

int[] a = new int[] { 1, 2, 3 }; 

foreach (int i in a.Concat(4)) 
{ 
    Console.Write(i); 
} 

將編譯生成的輸出:1234

谷歌搜索問題拋出了幾個SO問題,其中接受的答案表明,當期望達到這個目的時,最好的方法是簡單地做a.Concat(new int[] {4})。這是很好的(ISH),但在我看來有點「不乾淨」,因爲:

  • 也許有從宣佈一個新的數組(雖然這可能是將是微不足道的幾乎埃維時間)性能的下降
  • 它只是看起來並不整齊,易於閱讀和自然爲a.Concat(4)

任何人都知道爲什麼這樣的過載不存在?

此外,假設我的谷歌搜索沒有讓我失望 - 沒有類似的LINQ擴展方法採取類型T類型的單個元素。 (我明白,用自己的擴展方法來產生這種效果是非常容易的 - 但是這並不僅僅是使得ommision更奇怪嗎?我懷疑它會是一個理由,但不能想象它是什麼可能是)

UPDATE:

承認夫妻票關閉這個基於意見 - 我要澄清,我不是尋找是否這將是一個很好的補充LINQ人民的意見?

更多我在尋找理解爲什麼它不是LINQ的一部分的原因。

+3

沒有必要有遺漏的原因。包含一定有一個很好的理由。 –

+0

@HenkHolterman公平點,但恕我直言 - 我提到的幾個子彈點提供這個理由?沒有? –

+0

[_「每個功能在洞中以100分開始,這意味着它必須對整體套件產生重大的淨積極影響,才能使其成爲語言。」 msdn.com/b/ericgu/archive/2004/01/12/57985.aspx) –

回答

0

列入(一種或另一種形式)的一個很好的理由是IEnumerables更像功能序列單子。

但是由於LINQ直到.NET 3.0纔到達,並且主要使用擴展方法實現,所以我可以想象它們省略了在單個元素T上工作的擴展方法。這仍然是我的純粹推測。

但是他們確實包含了生成函數,它們不是擴展方法。具體如下:

  • Enumerable.Empty
  • Enumerable.Repeat
  • Enumerable.Range

你可以使用這些替代的自制軟件擴展方法。您提到的兩個用例可以解決爲:

int[] a = new int[] { 1, 2, 3 }; 

var myPrependedEnumerable = Enumerable.Repeat(0, 1).Concat(a); 
var myAppendedEnumerable = a.Concat(Enumerable.Repeat(4, 1)); 

如果將額外的重載作爲語法糖包含在內,它可能會很不錯。

Enumerable.FromElement(x); // or a better name (see below). 

缺乏一個明確的單位的功能是由Bart迪斯好奇和有趣的

在博客文章的有趣MoreLINQ series,使用System.Linq.EnumerableEx所示,後More LINQ with System.Interactive – Sequences under construction明確這個問題的交易,使用以下適當命名的方法構建單個元素IEnumerable

public static IEnumerable<TSource> Return<TSource>(TSource value); 

這只是返回功能(有時被稱爲單元)上的單子使用。

而且有趣的是,博客系列埃裏克利珀上monads,其具有以下報價在part eight

IEnumerable<int> sequence = Enumerable.Repeat<int>(123, 1); 

而且坦率地說,最後一個是有些冒險。我希望在Enumerable上有一個靜態方法,專門用於製作一個元素的序列。

此外,F#語言提供了seq類型:

序列由seq<'T>類型,這是對於IEnumerable的別名表示。因此,實現System.IEnumerable的任何.NET Framework類型都可以用作序列。

它提供了一個明確的單元功能Seq.singleton

結論

雖然沒有這爲我們提供了事實上的原因,闡明爲什麼這些序列結構都沒有明確出現在C#中,直到有人用設計決策過程中的股票知識那些信息,它確實突出了它值得了解更多。

+1

_「如果將額外的超載作爲語法糖加入,它可能會很好」_--爲什麼? 'Enumerable.FromElement(x)'比'new [] {x}'更好嗎? –

+0

@PeterDuniho我並不是說它更好。它會使意圖清楚:我想用一個元素實例化一個「IEnumerable 」,而不必選擇一個特定的'IEnumerable '實現,比如數組。推理與我更喜歡使用'IEnumerable.Empty '而不是'new int [0];'或'new int [] {}'這一事實並沒有什麼不同,因爲(獨立於靜態實例優化的原因) 。對於單個元素序列的潛在未來編譯器技術優化,也可能會受益,因爲實現對我們來說是隱藏的。 – Alex

+0

@PeterDuniho,我添加了一些額外的信息給我的答案,以澄清爲什麼它不會是奇怪的,如果這樣的生成函數存在,因爲它是「IEnumerable」單元的最基本的構造函數。 – Alex

-2

哲學問題,我喜歡。

起初,你可以很容易地擴展方法

public static IEnumerable<TSource> Concat(this IEnumerable<TSource> source, TSource element) 
{ 
    return source.Concat(new[]{element}); 
} 

創建行爲我認爲核心問題是IEnumerable的是一個不變的接口,它並不意味着在飛行中進行修改。

這可能(我用的可能是因爲我沒有在微軟工作,所以我可能是完全錯誤的)是同時修改的IEnumerable的部分不是那麼好發展(在你的意思的原因缺少一些方便的方法)。

如果您必須修改該集合,請考慮使用列表或其他接口。

+1

爲什麼連接單個元素與連接整個系列有什麼不同? –

+0

恐怕我沒有明確的答案。 我可以找到的唯一原因是,雖然它可能發生,你真的(異常)連接2枚枚舉,添加一個單一的元素應該永遠不會發生,因爲IEnumerable是不可變的。如果您將一個元素添加到IEnumerable中,也許您應該考慮使用IList實現。 也許Microsoft的工程師想要_underline_這個概念省略了單一的添加方法。對你有意義嗎? – Vincenzo

0

首先 - 您的谷歌搜索很好 - 沒有這樣的方法。我喜歡這個主意。這是一個用例,如果你跑進去,那會很棒。

我懷疑它沒有包含在LINQ API中,因爲設計者沒有看到它的共同需求。這只是我的猜想。

你說的僅僅用一個元素創建一個數組並不是那麼直觀。你可以得到手感和性能,你打算用這樣的:

public static class EnumerableExtensions { 
    public static IEnumerable<T> Concat<T>(this IEnumerable<T> source, T element) { 
     foreach (var e in source) { 
      yield return e; 
     } 
     yield return element; 
    } 

    public static IEnumerable<T> Concat<T>(this T source, IEnumerable<T> element) { 
     yield return source; 
     foreach (var e in element) { 
      yield return e; 
     } 

    } 
} 

class Program 
{ 
    static void Main() 
    { 
     List<int> ints = new List<int> {1, 2, 3}; 
     var startingInt = 0; 

     foreach (var i in startingInt.Concat(ints).Concat(4)) { 
      Console.WriteLine(i); 
     } 
    } 
} 

輸出:

0 
1 
2 
3 
4 
  • 懶惰的評價
  • 類似地實現對內置的LINQ的方法(它們實際上返回一個內部迭代器,而不是直接產生)
  • 參數檢查不會傷害它