How to implement a complex IEnumerable<T> directly inside the type containing the IEnumerable<T> property?
I have a generic collection implementation for various things that's inside:
public class ImageDocument
with properties like:
.Objects
.Effects
.Layers
each of which is basically IEnumerable<T>
, but I 开发者_高级运维also have separate calls that gives me the count for each of these, something like:
GetNumObjects()
GetNumEffects()
GetNumLayers()
but these are lower level members that I want to wrap as well as implement the above properties (.Objects, .Effects, .Layers
) as IEnumerable<T>
, also using lower level members like:
GetObject (int index)
GetEffect (int index)
GetLayer (int index)
I have my own IEnumerable<T>
like interface that inherits from IEnumerable<T>
.
In the end I want these properties to be like this:
ICountableEnumerable Objects
ICountableEnumerable Effects
ICountableEnumerable Layers
so I could both enumerate them, access their counts (using the low level functions) as well as to be able to index them:
myImageDocument.Objects.Count, etc.
myImageDocument.Objects[4]
foreach ... myImageDocument.Objects ...
Can I implement these directly just like implementing IEnumerable<T>
inside ImageDocument
like:
public IEnumerator<Objects> GetEnumerator()
{
foreach(...)
{
yield return obj;
}
}
or do I need an intermediate type for each of these properties? Something like:
ObjectCollection
EffectCollection
LayerCollection
that implements ICountableEnumerable
?
I would probably do something like:
class ImageDocument
{
public ReadOnlyCollection<Effect> Effects { get { ... } }
public ReadOnlyCollection<Layer> Layers { get { ... } }
...
That way the user can use all the nice properties of ReadOnlyCollection, like count, etc. The read-only-collection is a wrapper around a mutable collection; you can keep your mutable collection logic working as an implementation detail, and just expose a read-only wrapper on top of it.
What if within your class you held the collections as List < T >? Then your IEnumerable < T > .Objects, et al, can return the List which would be enumerable AND optimized for index and count by LINQ.
I would suggest declaring a struct type for each of the different styles of enumeration; the struct should hold an immutable reference to the base collection, and implement IEnumerable<appropriateType> and publicly expose a GetEnumerator method, which would in turn call baseThing.GetLayersEnumerator() or some other similar function. Such an approach would avoid boxing in many common usage scenarios, and--unlike the structs returned by things like List.GetEnumerator--would exhibit reference semantics whether or not it was boxed.
精彩评论