implement IEnumerator and IEnumerable in ICollection - c#

I am very new to this ICollection stuff and need some guidance of how to implement the IEnumerable and IEnumerator. I have checked Microsoft documentation and I think I understand what was said there (I think). But when I tried to implement it in my case, I was a bit confused and may need some clarification.
Basically, I declared a class T, then another class Ts which implemented ICollection. In Ts, I have a dictionary.
From the main program, I would like to initialize the class Ts like this:
Ts ts= new Ts(){{a,b}, {c,d}};
so, my questions are:
1) is it legal to do that? It appears that it is as the compiler did not complaint although I have not run the test because I have not thoroughly implement IEnumerable and IEnumerator, which brought to my 2nd question
2) How do I implement IEnumerable and IEnumerator?
Below is my pseudo code to illustrate my points.
public class T
{
string itemName;
int quantity;
.....
public T(string s, int q)
{
.....
}
}
public class Ts: ICollection
{
private Dictionary<string, T> inventory= new Dictionary<string,T>();
public void Add(string s, int q)
{
inventory.Add(s, new T(s,q));
}
public IEnumerator<T> GetEnumerator()
{
// please help
}
IEnumerator IEnumerable.GetEnumerator()
{
// what is the proper GetEnumerator here
}
...
implement other method in ICollection
}
extract from the main program
public Ts CollectionOfT = new Ts(){{"bicycle",100},{"Lawn mower",50}};
.........

The proper implementation is to cast your collection to IEnumerable in the explicit implementation:
IEnumerator IEnumerable.GetEnumerator() {
return ((IEnumerable)your_collection_here).GetEnumerator();
}
For the generic version, call GetEnumerator on your collection:
public IEnumerator<T> GetEnumerator() {
return your_collection_here.GetEnumerator();
}
You must have something that is backing your custom collection.. such as a List, Array, etc. Use that in those implementations.

Honestly you don't need to build your own collection "wrapper" around a Dictionary, but if you must, you can delegate pretty much all the calls to the dictionary for the implementation of the ICollection interface.
Hope this helps
public class Ts: ICollection<T>
{
private Dictionary<string, T> inventory= new Dictionary<string,T>();
//public void Add(string s, int q)
//{
// inventory.Add(s, new T(s,q));
//}
public void Add(T item)
{
inventory.Add(item.ItemName,item);
}
public void Add(string s, int q)
{
inventory.Add(s, new T(s, q));
}
public void Clear()
{
inventory.Clear();
}
public bool Contains(T item)
{
return inventory.ContainsValue(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
inventory.Values.CopyTo(array, arrayIndex);
}
public int Count
{
get { return inventory.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
return inventory.Remove(item.ItemName);
}
public System.Collections.Generic.IEnumerator<T> GetEnumerator()
{
return inventory.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return inventory.Values.GetEnumerator();
}
}
class Program
{
Ts ts = new Ts { { "a", 1 }, { "b", 2 } };
foreach (T t in ts)
{
Console.WriteLine("{0}:{1}",t.ItemName,t.Quantity);
}
}

Related

C# HashSet<T> read-only workaround

Here is this sample code:
static class Store
{
private static List<String> strList = new List<string>();
private static HashSet<String> strHashSet = new HashSet<string>();
public static List<String> NormalList
{
get { return strList; }
}
public static HashSet<String> NormalHashSet
{
get { return strHashSet; }
}
public static IReadOnlyList<String> ReadonlyList
{
get { return (IReadOnlyList<String>)strList; }
}
public static IReadOnlyCollection<String> ReadonlyHashSet
{
get { return (IReadOnlyCollection<String>)strHashSet; }
}
public static IReadOnlyList<String> Real_ReadonlyList
{
get { return (IReadOnlyList<String>)strList.AsReadOnly(); }
}
public static IReadOnlyCollection<String> Real_ReadonlyHashSet
{
get
{
List<String> tmpList = new List<String>(strHashSet);
return (IReadOnlyList<String>)(tmpList).AsReadOnly();
}
}
}
And here is a test code:
// normal behaviour
// you can modify the list and the hashset
Store.NormalList.Add("some string 1");
Store.NormalHashSet.Add("some string 1");
// tricky behaviour
// you can still modify the list and the hashset
((List<String>)Store.ReadonlyList).Add("some string 2");
((HashSet<String>)Store.ReadonlyHashSet).Add("some string 2");
// expected read-only behaviour
// you can NOT modify
// throws InvalidCastException
((List<String>)Store.Real_ReadonlyList).Add("some string 3");
// throws InvalidCastException
((HashSet<String>)Store.Real_ReadonlyHashSet).Add("some string 3");
My questions are these:
Is there a better solution for the "Real_ReadonlyHashSet" property?
Will Microsoft some day implement the "AsReadOnly" method to the HashSet<T>?
Here is the entirety of the code of .AsReadOnly()
public ReadOnlyCollection<T> AsReadOnly() {
Contract.Ensures(Contract.Result<ReadOnlyCollection<T>>() != null);
return new ReadOnlyCollection<T>(this);
}
The first line is not even necessary if you are not using CodeContracts. However, ReadOnlyCollection<T> only supports IList<T> which HashSet<T> does not support.
What I would do is make your own ReadOnlySet<T> class that takes in a ISet<T> and only passes through the read operations like ReadOnlyCollection<T> does internally.
UPDATE:
Here is a fully fleshed out ReadOnlySet<T> I quickly wrote up along with a extension method that adds a .AsReadOnly() on to anything that implements ISet<T>
public static class SetExtensionMethods
{
public static ReadOnlySet<T> AsReadOnly<T>(this ISet<T> set)
{
return new ReadOnlySet<T>(set);
}
}
public class ReadOnlySet<T> : IReadOnlyCollection<T>, ISet<T>
{
private readonly ISet<T> _set;
public ReadOnlySet(ISet<T> set)
{
_set = set;
}
public IEnumerator<T> GetEnumerator()
{
return _set.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable) _set).GetEnumerator();
}
void ICollection<T>.Add(T item)
{
throw new NotSupportedException("Set is a read only set.");
}
public void UnionWith(IEnumerable<T> other)
{
throw new NotSupportedException("Set is a read only set.");
}
public void IntersectWith(IEnumerable<T> other)
{
throw new NotSupportedException("Set is a read only set.");
}
public void ExceptWith(IEnumerable<T> other)
{
throw new NotSupportedException("Set is a read only set.");
}
public void SymmetricExceptWith(IEnumerable<T> other)
{
throw new NotSupportedException("Set is a read only set.");
}
public bool IsSubsetOf(IEnumerable<T> other)
{
return _set.IsSubsetOf(other);
}
public bool IsSupersetOf(IEnumerable<T> other)
{
return _set.IsSupersetOf(other);
}
public bool IsProperSupersetOf(IEnumerable<T> other)
{
return _set.IsProperSupersetOf(other);
}
public bool IsProperSubsetOf(IEnumerable<T> other)
{
return _set.IsProperSubsetOf(other);
}
public bool Overlaps(IEnumerable<T> other)
{
return _set.Overlaps(other);
}
public bool SetEquals(IEnumerable<T> other)
{
return _set.SetEquals(other);
}
public bool Add(T item)
{
throw new NotSupportedException("Set is a read only set.");
}
public void Clear()
{
throw new NotSupportedException("Set is a read only set.");
}
public bool Contains(T item)
{
return _set.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
_set.CopyTo(array, arrayIndex);
}
public bool Remove(T item)
{
throw new NotSupportedException("Set is a read only set.");
}
public int Count
{
get { return _set.Count; }
}
public bool IsReadOnly
{
get { return true; }
}
}
Starting from .NET 5, the HashSet<T> class now implements the IReadOnlySet<T> interface. There is no built-in ReadOnlySet<T> wrapper though, analogous to the existing ReadOnlyDictionary<TKey, TValue> class for dictionaries, but implementing one is trivial:
public class ReadOnlySet<T> : IReadOnlySet<T>
{
private readonly ISet<T> _set;
public ReadOnlySet(ISet<T> set) { ArgumentNullException.ThrowIfNull(set); _set = set; }
public int Count => _set.Count;
public bool Contains(T item) => _set.Contains(item);
public bool IsProperSubsetOf(IEnumerable<T> other) => _set.IsProperSubsetOf(other);
public bool IsProperSupersetOf(IEnumerable<T> other) => _set.IsProperSupersetOf(other);
public bool IsSubsetOf(IEnumerable<T> other) => _set.IsSubsetOf(other);
public bool IsSupersetOf(IEnumerable<T> other) => _set.IsSupersetOf(other);
public bool Overlaps(IEnumerable<T> other) => _set.Overlaps(other);
public bool SetEquals(IEnumerable<T> other) => _set.SetEquals(other);
public IEnumerator<T> GetEnumerator() => _set.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
The upcoming .NET 7 will also feature a new AsReadOnly extension method for IDictionary<TKey,TValue>s, so let's make one for ISet<T>s too:
public static ReadOnlySet<T> AsReadOnly<T>(this ISet<T> set) => new ReadOnlySet<T>(set);
Usage example:
HashSet<Item> items = new();
ReadOnlySet<Item> readOnlyItems = items.AsReadOnly();
You could write your own implementation of an IReadOnlyCollection<T> that wraps an IEnumerable<T> and a count:
public sealed class ReadOnlyCollectionFromEnumerable<T>: IReadOnlyCollection<T>
{
readonly IEnumerable<T> _data;
public ReadOnlyCollectionFromEnumerable(IEnumerable<T> data, int count)
{
_data = data;
Count = count;
}
public IEnumerator<T> GetEnumerator()
{
return _data.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int Count { get; }
}
Then you declare your ReadonlyHashSet property like this:
public static IReadOnlyCollection<String> ReadonlyHashSet
{
get { return new ReadOnlyCollectionFromEnumerable<string>(strHashSet, strHashSet.Count); }
}
I think that would solve the issue.
HashSet implements the IReadOnlyCollection interface starting
with the .NET Framework 4.6; in previous versions of the .NET
Framework, the HashSet class did not implement this interface.
Read in learn.microsoft.com
In .NET Framework 4.6 release, the HashSet implements IReadOnlyCollection interface along with the ISet interface. link...
It does seem to.
You could also do this but maybe take a performance hit:
var foo = (IReadOnlyCollection<string>) mySet.toList();

C# HashSet2 to work exactly like the standard C# HashSet, not compiling

I'm creating my own HashSet that works as the standard HashSet, using a Dictionary. I'm doing this because C# for XNA XBox doesn't support HashSets.
This code is based on code from an example I found. I've edited the example to fix some of the problems but it still won't compile.
public class HashSet2<T> : ICollection<T>
{
private Dictionary<T, Int16> dict;
// code has been edited out of this example
// see further on in the question for the full class
public IEnumerator<T> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return dict.GetEnumerator();
}
}
.
'HashSet2<T>' does not implement interface member
'System.Collections.IEnumerable.GetEnumerator()'.
'HashSet2<T>.GetEnumerator()' cannot implement
'System.Collections.IEnumerable.GetEnumerator()'
because it does not have the matching return type of
'System.Collections.IEnumerator'
I'd also be grateful for information on fixing it to be more like the standard HashSet if it deviates in it's behaviour or what it implments in ways that could be unexpected.
Continued from: stackoverflow.com/questions/9966336/c-sharp-xna-xbox-hashset-and-tuple
The most recent vertion of the class:
public class HashSet2<T> : ICollection<T>
{
private Dictionary<T, Int16> dict;
// Dictionary<T, bool>
public HashSet2()
{
dict = new Dictionary<T, short>();
}
public HashSet2(HashSet2<T> from)
{
dict = new Dictionary<T, short>();
foreach (T n in from)
dict.Add(n, 0);
}
public void Add(T item)
{
// The key of the dictionary is used but not the value.
dict.Add(item, 0);
}
public void Clear()
{
dict.Clear();
}
public bool Contains(T item)
{
return dict.ContainsKey(item);
}
public void CopyTo(
T[] array,
int arrayIndex)
{
throw new NotImplementedException();
}
public bool Remove(T item)
{
return dict.Remove(item);
}
public System.Collections.IEnumerator GetEnumerator()
{
return ((System.Collections.IEnumerable)
dict.Keys).GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return ((IEnumerable<T>)
dict.Keys).GetEnumerator();
}
public int Count
{
get {return dict.Keys.Count;}
}
public bool IsReadOnly
{
get {return false;}
}
}
You want to enumerate the keys, not the dictionary. Try this:
public IEnumerator GetEnumerator()
{
return ((IEnumerable)dict.Keys).GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return ((IEnumerable<T>)dict.Keys).GetEnumerator();
}
The point is that the HashSet's GetEnumerator returns enumerator that enumerates keys of type T while dictionary's GetEnumerator returns enumerator that enumerates KeyValue object.
UPDATE
Change it to below:
public IEnumerator GetEnumerator()
{
dict.Keys.GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return dict.Keys.GetEnumerator();
}
You can simply use Mono's HashSet<T>. You might need to make some minor changes to #if, or remove some interfaces/attributes, but it works on .net.
It's using the MIT X11 license, which is permissive. https://github.com/mono/mono/blob/master/mcs/class/System.Core/System.Collections.Generic/HashSet.cs
Just took a look at the source, and all implementations of GetEnumerator in the Dictionary<TKey, TValue> return the KeyCollection.Enumerator/ValueCollection.Enumerator objects instead of IEnumerator<T> (which is what we need). The good news is that the Key/ValueCollation.Enumerator implement both System.Collection.IEnumerator and IEnumerator<T> interfaces, so you can safely cast to those types.
Try doing this instead:
public IEnumerator GetEnumerator()
{
return (IEnumerator)dict.Keys.GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return (IEnumerator<T>)dict.Keys.GetEnumerator();
}

Cast issues between generic list and CollectionDataContract

I have the following collection contract defined:
[CollectionDataContract(Name = "Centres")]
public class Centres : List<Centre>
{}
and the following operation contract defined to return this collection
public Model.Centres GetCentres()
{
List<Centre> allCentres = (from c in Model.Centre.GetCentres()
where c.Visible == true
select c).ToList();
return allCentres
}
But when I run the code I receive an ExplicitCastException. So as far as I can see I'm trying to cast a list of centres (List) into my collection 'Centres' which itself derives from List. Is this possible or by deriving a new object am I creating a new type of list that won't work in this way.
My current work around for this problem is to declare a new instance of Centres and copy all centres into it using a foreach.
The problem is Centres "is a" List<Centre>, List<Centre> is not a Centres.
Despite Centres having no implementation it is still a sub-class of List<Centre>, you could extend your Centres class to have an implicit conversion operator or, perhaps add a constructor to Centres that takes a List<Centre> as a parameter.
Try changing Centres to somthing like ...
[CollectionDataContract(Name = "Centres")]
public class Centres : List<Centre>
{
public static implicit operator Centres(List<Centre> l)
{
Centres newCentres = new Centres();
newCentres.AddRange(l);
return newCentres;
}
}
Then it will allow implicit conversion from List<Centre>.
What you are trying wont work.
If possible you should consider refactoring Centres to a has a List<Centre> more than is a relationship or at least define a constructor that takes an IEnumerable<Centre>
This way you would be able to write:
Centres allCentres = new Centres(from c in Model.Centres.GetCentres()
where c.Visible == true
select c);
Of course it all depends on your specific situation where this might not be a valid solution.
What you can do is create your own implementation of the IList<T> interface that wraps an IList.
It takes more code, but will not be as slow as to copy all the objects:
[CollectionDataContract(Name = "Centres")]
public class Centres : IList<Centre>
{
private IList<Centre> _inner;
private IList<Centre> Inner
{
get
{
if (_inner == null)
_inner = new List<Centre>();
return _inner;
}
}
public Centres(List<Centre> items)
{
_inner = items;
}
#region IList<Centre> Members
public int IndexOf(Centre item)
{
return Inner.IndexOf(item);
}
public void Insert(int index, Centre item)
{
Inner.Insert(index, item);
}
public void RemoveAt(int index)
{
Inner.RemoveAt(index);
}
public Centre this[int index]
{
get
{
return Inner[index];
}
set
{
Inner[index] = value;
}
}
#endregion
#region ICollection<Centre> Members
public void Add(Centre item)
{
Inner.Add(item);
}
public void Clear()
{
Inner.Clear();
}
public bool Contains(Centre item)
{
return Inner.Contains(item);
}
public void CopyTo(Centre[] array, int arrayIndex)
{
Inner.CopyTo(array, arrayIndex);
}
public int Count
{
get { return Inner.Count; }
}
public bool IsReadOnly
{
get { return Inner.IsReadOnly; }
}
public bool Remove(Centre item)
{
return Inner.Remove(item);
}
#endregion
#region IEnumerable<Centre> Members
public IEnumerator<Centre> GetEnumerator()
{
return Inner.GetEnumerator();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return Inner.GetEnumerator();
}
#endregion
}

C# - Can a List<MyClass> be seamlessly cast to a List<Interface> or similar?

I have a DataSource in my control which is always a List<T> where T has to inherit from IEntity.
public class MyClass<T> where T : IEntity
{
public List<T> DataSource
{
get;
set;
}
}
Now, obviously you can't cast a List<T> to a List<IEntity> doing the following:
List<IEntity> wontWork = (List<IEntity>)this.DataSource;
How can I get the DataSource as a List of IEntity, whilst still being able to add and remove items from the DataSource? I.e. I could do the following, but removing from the List it returns would not remove from the DataSource:
public List<TOut> GetDataSourceCopyAsUnderlyingType<TOut>()
{
if (this.DataSource == null)
{
return new List<TOut>();
}
else
{
// Get the list and the enumerator
IList list = (IList)this.DataSource;
IEnumerator enumerator = list.GetEnumerator();
// Build the target list
List<TOut> targetList = new List<TOut>();
int i = 0;
while (enumerator.MoveNext())
{
TOut entity = (TOut)list[i];
targetList.Add(entity);
i++;
}
return targetList;
}
}
Basically, I need some way of doing the following:
List<IEntity> interfaceList = this.GetDataSourceAsAnotherType<IEntity>();
int dataSourceCount = this.DataSource.Count; // Equals 5
int interfaceCount = interfaceList.Count; // Equals 5
interfaceList.RemoveAt(0);
int dataSourceCount = this.DataSource.Count; // Equals 4
int interfaceCount = interfaceList.Count; // Equals 4
And just to add, I don't mind if it means I've got to use a different type instead of a List.
EDIT: Sorry, forgot to say I'm using .Net2.0 and cannot move to .Net 3.5.
It would be a monumentally bad idea if this were allowed, which is why it isn't. I can add any old IEntity to a List<IEntity> which will blow up if that IEntity can't be cast to T. Whilst all Ts are IEntities, not all IEntities are Ts.
This works with arrays because arrays have a deliberate subtyping hole (as they do in Java). Collections do not have a subtyping hole.
Create a wrapper class that seamlessly converts. Untested sample:
public class CastList<TTarget, TOriginal>
: IList<TTarget> where TOriginal : TTarget
{
List<TOriginal> _orig;
public CastList(List<TOriginal> orig) { _orig = orig; }
public Add(TTarget item) { _orig.Add(item); }
public TTarget this[int i]
{
get { return (TTarget)_orig[i]; }
set { _orig[i] = value; }
}
public IEnumerator<TTarget> GetEnumerator()
{
foreach(TOriginal item in _orig)
yield return (TTarget)item;
}
// etc...
}
Manipulations of the original list will also be reflected in the wrapper. To use this, just construct it with your DataSource.
What DrPizza said, but with more code:
public class ListFacade<TIn, TOut> : IList<TOut> where TIn : TOut
{
private readonly IList<TIn> innerList;
public ListFacade(IList<TIn> innerList)
{
this.innerList = innerList;
}
public int Count
{
get { return this.innerList.Count; }
}
public bool IsReadOnly
{
get { return this.innerList.IsReadOnly; }
}
public TOut this[int index]
{
get { return this.innerList[index]; }
set { this.innerList[index] = (TIn)value; }
}
public void Add(TOut item)
{
this.innerList.Add((TIn)item);
}
public void Clear()
{
this.innerList.Clear();
}
public bool Contains(TOut item)
{
return (item is TIn) && this.innerList.Contains((TIn)item);
}
public void CopyTo(TOut[] array, int arrayIndex)
{
var inArray = new TIn[this.innerList.Count];
this.innerList.CopyTo(inArray, arrayIndex);
Array.Copy(inArray, array, inArray.Length);
}
public IEnumerator<TOut> GetEnumerator()
{
foreach (var item in this.innerList)
{
yield return item;
}
}
System.Collections.IEnumerator
System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public int IndexOf(TOut item)
{
return (item is TIn) ? this.innerList.IndexOf((TIn)item) : -1;
}
public void Insert(int index, TOut item)
{
this.innerList.Insert(index, (TIn)item);
}
public bool Remove(TOut item)
{
return (item is TIn) && this.innerList.Remove((TIn)item);
}
public void RemoveAt(int index)
{
this.innerList.RemoveAt(index);
}
Add, Insert and the indexer set will blow up if the argument is not of type TIn.
ok this might be completely beside the point but, how about using a little bit of Linq?
var interfaceList = objectList.ConvertAll<Interface>(o => (Interface)o);
this way you can cast the objectList easily.
hope this helps to find the solution...
I'm in favor of linq too, but you can do it like:
var interfaceList = objectList.Cast<IEntity>();
Which is shorter and more expressive.

In C# 4.0 why can't an out parameter in a method be covariant?

Given this magical interface:
public interface IHat<out TRabbit>
{
TRabbit Take();
}
And this class hierarchy:
public class Rabbit { }
public class WhiteRabbit : Rabbit { }
I can now compile this:
IHat<WhiteRabbit> hat1 = null;
IHat<Rabbit> hat2 = hat1;
Which is great. But what if I define the interface differently:
public interface IHat<out TRabbit>
{
bool Take(out TRabbit r);
}
I'm indicating that the hat might be empty, using a separate boolean return value (the previous version would perhaps have returned a null rabbit from an empty hat). But I'm still only outputting a rabbit, so not doing anything logically different to the previous version.
The C# 4.0 compiler in the CTP gives an error in the interface definition - it requires 'out' method parameters to be of an invariant type. Is there a hard-and-fast reason why this isn't allowed, or is it something that might be addressed in a future version?
Interesting. However, at the CLI level there is no such thing as "out" - only "ref"; there is an attribute that helps compilers (for definite assignment) that says "you don't need to pass it in".
Maybe this restriction is because the CLI doesn't have "out", only "ref".
Although it's a bit of a hassle, you can use a covariance wrapper:
public class CovariantListWrapper<TOut, TIn> : IList<TOut> where TIn : TOut
{
IList<TIn> list;
public CovariantListWrapper(IList<TIn> list)
{
this.list = list;
}
public int IndexOf(TOut item)
{
// (not covariant but permitted)
return item is TIn ? list.IndexOf((TIn)item) : -1;
}
public TOut this[int index]
{
get { return list[index]; }
set { throw new InvalidOperationException(); }
}
public bool Contains(TOut item)
{
// (not covariant but permitted)
return item is TIn && list.Contains((TIn)item);
}
public void CopyTo(TOut[] array, int arrayIndex)
{
foreach (TOut t in this)
array[arrayIndex++] = t;
}
public int Count { get { return list.Count; } }
public bool IsReadOnly { get { return true; } }
public IEnumerator<TOut> GetEnumerator()
{
foreach (TIn t in list)
yield return t;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Insert(int index, TOut item) { throw new InvalidOperationException(); }
public void RemoveAt(int index) { throw new InvalidOperationException(); }
public void Add(TOut item) { throw new InvalidOperationException(); }
public void Clear() { throw new InvalidOperationException(); }
public bool Remove(TOut item) { throw new InvalidOperationException(); }
}
This lets you keep the collection as it was originally typed and refer to it covariantly without creating a detached copy, so that updates to the original are seen in the covariant use. Example:
class CovarianceWrapperExample
{
class Person { }
class Employee : Person { }
void ProcessPeople(IList<Person> people) { /* ... */ }
void Foo()
{
List<Employee> employees = new List<Employee>();
// cannot do:
ProcessPeople(employees);
// can do:
ProcessPeople(new CovariantListWrapper<Person, Employee>(employees));
}
}

Categories

Resources