J'ai rencontré un cas où le fait que List.AsReadOnly()
renvoie un ReadOnlyCollection
au lieu d'un IReadOnlyCollection
a rendu les choses difficiles pour moi. Comme la collection retournée était la Value
d'un Dictionary
, elle ne pouvait pas être automatiquement mise à jour à IReadOnlyCollection
. Cela semblait étrange, et après examen du code source .Net, j'ai confirmé que la méthode AsReadOnly()
fait quelque chose de différent pour List
que pour Dictionary
, à savoir renvoyer la classe concrète au lieu de l'interface.Pourquoi List.AsReadOnly renvoie-t-il un ReadOnlyCollection mais Dictionary.AsReadOnly renvoie un IReadOnlyDictionary?
Quelqu'un peut-il expliquer pourquoi c'est? Il semble que ce soit un mauvais service d'avoir cette incohérence, surtout parce que nous voulons utiliser les interfaces quand c'est possible et surtout quand il est public.
Dans mon code, je pensais d'abord que puisque mon client était juste une méthode privée, je pouvais changer sa signature de paramètre de IReadOnlyDictionary<T, IReadOnlyCollection<T>>
à IReadOnlyDictionary<T, ReadOnlyCollection<T>>
. Mais, je compris que ce fait ressembler à la méthode privée pourrait modifier les valeurs de collecte, donc je mets un casting explicite gênant dans le code précédent afin de pouvoir utiliser correctement l'interface:
.ToDictionary(
item => item,
item => (IReadOnlyCollection<T>) relatedItemsSelector(item)
.ToList()
.AsReadOnly() // Didn't expect to need the direct cast
)
Oh, et depuis Je vois toujours la covariance et la contravariance confuses, est-ce que quelqu'un pourrait me dire lequel empêche la distribution automatique et essayer de me rappeler de façon raisonnable comment se souvenir d'eux pour l'avenir? (par exemple, les collections ne sont pas ______ variable [co/contra] pour _____ [entrée/sortie] paramètres.) Je comprends pourquoi cela ne peut pas être, car il peut y avoir de nombreuses implémentations de l'interface et il n'est pas sûr de jeter tous les éléments individuels du dictionnaire au type demandé. Sauf si je souffle même cet aspect simple et je ne le comprends pas, dans ce cas, j'espère que vous pouvez m'aider à corriger ...
Oh oh oh! Je supposais qu'il ne se lancerait pas automatiquement car il * n'était pas * covariant, mais maintenant je vois que précisément parce que 'IReadOnlyCollection' est en lecture seule, le compilateur peut voir qu'il est sûr de transtyper du type dérivé à la base . Donc, si c'est le cas, pourquoi ai-je dû faire une distribution explicite? – ErikE
La covariance et la contravariance ne se produisent que lorsque vous transtypez entre deux * interfaces * génériques et modifiez le * paramètre de type * (de base à dérivé ou vice-versa). Le casting que vous avez utilisé est juste une distribution - c'est permis parce que ReadOnlyCollection 'implémente' IReadOnlyList '. –
Oh, oups, ça a du sens. Cela devient plus clair. Pourquoi ne pouvait-il pas implicitement jeter? – ErikE