admin管理员组文章数量:1122846
I want to create a read-only interface for my Box class. Box contains bananas. Bananas have a read-only interface IBananaRead.
The problem is, that in the box code I do all operations with List<Banana>
but in the read only interface I want the other class to have access not to Banana but to IBananaReads. How to solve this type of situations?
class Box: IBoxRead
{
List<Banana> bananas;
}
interface IBoxRead {
List<IBananaRead> bananas;
}
I could create a duplicate list of IBananaRead interfaces in the Box but that doesn't seem right due to duplication.
class Box: IBoxRead
{
List<Banana> bananas;
List<IBananaRead> bananaReads;
}
interface IBoxRead {
List<IBananaRead> bananaReads;
}
The end goal is to have two types of interactions with the Box:
// A read-only class iterates over:
foreach (IBananaRead b in instanceOfBoxRead.bananas)
{
b.ReadTheBanana();
}
// Another class that has right to edit the bananas in the box iterates
// using the class Banana, not the readonly interface of IBananaRead:
foreach (Banana b in instanceOfBox.bananas)
{
b.EditTheBanana();
}
I want to create a read-only interface for my Box class. Box contains bananas. Bananas have a read-only interface IBananaRead.
The problem is, that in the box code I do all operations with List<Banana>
but in the read only interface I want the other class to have access not to Banana but to IBananaReads. How to solve this type of situations?
class Box: IBoxRead
{
List<Banana> bananas;
}
interface IBoxRead {
List<IBananaRead> bananas;
}
I could create a duplicate list of IBananaRead interfaces in the Box but that doesn't seem right due to duplication.
class Box: IBoxRead
{
List<Banana> bananas;
List<IBananaRead> bananaReads;
}
interface IBoxRead {
List<IBananaRead> bananaReads;
}
The end goal is to have two types of interactions with the Box:
// A read-only class iterates over:
foreach (IBananaRead b in instanceOfBoxRead.bananas)
{
b.ReadTheBanana();
}
// Another class that has right to edit the bananas in the box iterates
// using the class Banana, not the readonly interface of IBananaRead:
foreach (Banana b in instanceOfBox.bananas)
{
b.EditTheBanana();
}
Share
Improve this question
asked Nov 22, 2024 at 8:43
luminousluminous
191 silver badge4 bronze badges
7
|
Show 2 more comments
2 Answers
Reset to default 3Covariance and contravariance in generics | Microsoft Learn
A List<T>
or IList<T>
is, by definition, invariant. You can't pass it around as an IList<U>
for either T : U
or U : T
.
If you could:
- For
T : U
, you could insert an instance ofV
, whereV : U
, which would mean theList<T>
would contain an item which was not an instance ofT
. - For
U : T
, you could have aList<U>
containing items which are not instances ofU
.
In this case, you want a covariant list. That means you need to use the IReadOnlyList<T>
interface, which is implemented by the List<T>
class. You can happily return a List<T>
as IReadOnlyList<U>
when T : U
.
However, a property of type List<T>
cannot implicitly implement an interface property of type IReadOnlyList<T>
, so you would need to implement that property explicitly. The explicit implementation can simply delegate to the List<T>
property.
This would give you:
interface IBoxRead
{
IReadOnlyList<IBananaRead> Bananas { get; }
}
class Box : IBoxRead
{
public List<Banana> Bananas { get; }
IReadOnlyList<IBananaRead> IBoxRead.Bananas => Bananas;
}
NB: This pattern would not prevent consumers of the IBoxRead
interface from directly casting the property to List<Banana>
and modifying the list. But by the same argument, they could also cast the IBoxRead
instance to a Box
, which would give them the same access.
Unless I'm missing something, all you need is this:
var boxList = new List<Box>();
// ...
var iBoxReadList = boxList.Cast<IBoxRead>().ToList();
That would need to be executed on demand, i.e. each time you need a list of read-only items, as it will not be updated along with the original list. You could declare a read-only property and create the new list in the getter.
That said, the second list should probably be read-only too, rather than just the items. Otherwise, the consumer could add items to the list to no good effect. In that case, you should probably do this:
var iBoxReadList = boxList.Cast<IBoxRead>().ToList().AsReadOnly();
That will create a ReadOnlyCollection<IBoxRead>
.
本文标签:
版权声明:本文标题:How to expose a List<Interface> when myClass has List<Class That Implements This Interface>? (C#) - 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736305079a1932463.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
SomethingElseThatImplementsIBananaRead
objects into this list? – Damien_The_Unbeliever Commented Nov 22, 2024 at 8:54List<T>
(whatever T actually is) inside theBox
. – Fildor Commented Nov 22, 2024 at 8:56