我碰到一個案例,List.AsReadOnly()
返回ReadOnlyCollection
而不是IReadOnlyCollection
這個事實讓我感到困難。由於返回的收藏是的Value
,因此無法自動上傳到IReadOnlyCollection
。這看起來很奇怪,經過對.Net源代碼的審查,我確認AsReadOnly()
方法爲List
做了一些不同於Dictionary
的操作,即返回具體類而不是接口。爲什麼List.AsReadOnly返回一個ReadOnlyCollection,但Dictionary.AsReadOnly返回一個IReadOnlyDictionary?
任何人都可以解釋爲什麼這是?這種不一致性似乎是不利的,特別是因爲我們希望在可能的情況下使用接口,特別是在公開時。
在我的代碼中,起初我在想,既然我的客戶只是一個私有方法,我可以將其參數簽名從IReadOnlyDictionary<T, IReadOnlyCollection<T>>
更改爲IReadOnlyDictionary<T, ReadOnlyCollection<T>>
。但是,後來我意識到,這使它看起來像私有方法可能會修改收藏價值,所以我把一個惱人的顯式轉換到前面的代碼,以便正確使用該接口:
.ToDictionary(
item => item,
item => (IReadOnlyCollection<T>) relatedItemsSelector(item)
.ToList()
.AsReadOnly() // Didn't expect to need the direct cast
)
哦,因爲我總是得到協變和矛盾的困惑,有人可以告訴我哪一個阻止自動演員,並試圖以合理的方式提醒我如何記住他們的未來? (例如,對於_____ [輸入/輸出]參數,集合不是______variant [co/contra])。我明白爲什麼不能這樣做,因爲接口可能有很多實現,並且不能安全地將所有字典中的單個元素添加到請求的類型。除非我吹這個簡單的方面,我不知道瞭解它,在這種情況下,我希望你能幫助我設置正確的...
哦,哦,哦!我假設它不會自動轉換,因爲它*不是*協變的,但現在我明白,因爲IReadOnlyCollection是隻讀的,編譯器可以看到從派生類型轉換爲基類是安全的。所以如果是這樣的話,爲什麼我必須做一個明確的演員? – ErikE
只有當您在兩個通用*接口*之間進行投射並更改*類型參數*(從基礎到派生或反之亦然)時纔會發生協變和逆變。您使用的演員陣容只是一個陣容 - 這是允許的,因爲'ReadOnlyCollection'實施'IReadOnlyList '。 –
哦,哎呀,這很有道理。它越來越清晰。爲什麼它不能隱式施放? – ErikE