2012-06-20 83 views
8

當我意識到F#的map同時實現了IDictionary <'Key',Value>和ICollection<KeyValuePair<'a, 'b>>考慮到兩者都支持作爲契約一部分的變化(添加和刪除)時,我有些驚訝。爲什麼F#map實現可變操作的接口?

看看map的執行情況,它只是當你試圖引起突變而已!

let map = [| (1, "one"); (2, "two") |] |> Map.ofArray 
let dict = map :> IDictionary<int, string> 
dict.Add(3, "three");; 

上述代碼拋出異常:

System.NotSupportedException:地圖值不能突變。在 Microsoft.FSharp.Collections.FSharpMap 2.System-Collections-Generic-IDictionary 2-添加在(TKEY的 K,TValue v)中。$ FSI_0007.main @()停止 由於錯誤

其是如預期。

對於一個不可變的集合,只有當該集合的使用者試圖引起變異時,才能將自身暴露爲可變集合,以便引發異常,這似乎是一個非常危險的決定。

我在這裏錯過了什麼嗎?

+2

['dict'](http://msdn.microsoft.com/en-us/library/ee353774.aspx)函數是另一個這樣的示例。它返回一個_read only_'IDictionary <_,_>'。 – Daniel

回答

6

IsReadOnly允許接口是隻讀的,即使它提供可寫的方法。

+0

好點,但它確實落在了消費者身上,總是要檢查該房產的價值,但我認爲這是公平的 – theburningmonk

4

這是一個.Net的東西。你不能只實現一些接口,但他們想要實現接口 - 因爲你可以使用它的查詢和轉換方法(所以你可以將它傳遞給從IDictionary`2讀取的函數)。

9

我認爲主要原因是.NET沒有任何接口代表不可變(字典接口的一部分)。這意味着所有.NET API都必須以IDictionary<K, V>作爲參數,即使它們只打算從字典中讀取。所以:

  • 實施IDictionary<'K, 'V>是相當多的,使F#一成不變的地圖可用作爲參數傳遞給那些需要支持查找對象的任何.NET庫的唯一途徑。可悲的是,在.NET中沒有隻讀選擇。

  • 實施ICollection<KeyValuePair<'K, 'V>>對我沒有太大意義,因爲有一個只讀的替代IEnumerable<KeyValuePair<'K, 'V>>和不可變映射也實現此接口。

    但也許有一些.NET庫取得ICollection<'T>(爲了有效 - 即得到Count而不枚舉所有元素)並以只讀方式使用它。

    編輯:正如丹尼爾的評論指出,實施ICollection是必需的,因爲IDictionary接口從它繼承。

我認爲缺乏只讀接口是相當不幸的,但有可能是沒有辦法,這可能是固定的,因爲這將意味着改變現有的.NET集合庫。

+3

'Map'必須實現'ICollection >',因爲['IDictionary <_,_>'](http://msdn.microsoft.com/en-us/library/s4ys34ea.aspx)繼承它。 – Daniel

+0

@丹尼爾大點 - 謝謝!我會編輯答案。 –

相關問題