How can you return a Collection as a Collection?

C# doesn't support generic collections covariance (it's only supported for arrays). I use an adapter class in such cases. It just redirects all calls to the actual collection, converting values to the required type (doesn't require copying all list values to the new collection).

Usage looks like this: Collection IBucket. Nails { get { return new ListAdapter(nails); } } // my implementation (it's incomplete) public class ListAdapter : IList { public ListAdapter(IList val) { _vals = val; } IList _vals; protected static T_Src ConvertToSrc(T_Dst val) { return (T_Src)((object)val); } protected static T_Dst ConvertToDst(T_Src val) { return (T_Dst)((object)val); } public void Add(T_Dst item) { T_Src val = ConvertToSrc(item); _vals. Add(val); } public void Clear() { _vals.Clear(); } public bool Contains(T_Dst item) { return _vals.

Contains(ConvertToSrc(item)); } public void CopyTo(T_Dst array, int arrayIndex) { throw new NotImplementedException(); } public int Count { get { return _vals. Count; } } public bool IsReadOnly { get { return _vals. IsReadOnly; } } public bool Remove(T_Dst item) { return _vals.

Remove(ConvertToSrc(item)); } public IEnumerator GetEnumerator() { foreach (T_Src cur in _vals) yield return ConvertToDst(cur); } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } public override string ToString() { return string. Format("Count = {0}", _vals. Count); } public int IndexOf(T_Dst item) { return _vals.

IndexOf(ConvertToSrc(item)); } public void Insert(int index, T_Dst item) { throw new NotImplementedException(); } public void RemoveAt(int index) { throw new NotImplementedException(); } public T_Dst thisint index { get { return ConvertToDst(_valsindex); } set { _valsindex = ConvertToSrc(value); } } }.

That kind of looks like overkill at this point.... – RCIX Aug 26 '09 at 5:26 It's overkill if you only need it once, but this class makes life easier when you need covariance more oftenly. – skevar7 Aug 26 '09 at 5:27 Cool, I think this is exactly what I need! – jameswelle Aug 28 '09 at 21:21.

C# 3.0 generics are invariant. You can't do that without creating a new object. C# 4.0 introduces safe covariance/contravariance which won't change anything about read/write collections (your case) anyway.

1 It is a solution but if you want a collection of Nail object only, it is a problem because every object implementing INail could be added in the collection. – Francis B. Aug 26 '09 at 2:42 I would live with this until C#4.

Of course this is up to the original poster. – ChaosPandion Aug 26 '09 at 2:45 1 I should have mentioned that these classes are serialized using the XmlSerializer, which is why the collection has to be defined as Collection and not Collection. – jameswelle Aug 26 '09 at 4:01.

Why not just return it as an interface, just have all your public methods in the interface, that way you don't have this problem, and, if you later decide to return another type of Nail class then it would work fine.

It's the age-old issue that C# 3.0 and down doesn't support co-variance; you need to cast nails to INail for it to compile. C# 4.0 will address this.

Casting nails to Collection doesn't compile. I mentioned this in the original question. – jameswelle Aug 26 '09 at 4:01 You mention boxing, not Casting (see my answer for the difference in this case) – johnc Aug 26 '09 at 4:25 Are you saying that the (nails as Collection) is a boxing operation, not a casting operation?

Msdn.microsoft.Com/en-us/library/cscsdfbt%28VS.71%29. Aspx – jameswelle Aug 26 '09 at 4:33 It is my understanding that boxing occurs on value types, which are not used here. – jameswelle Aug 26 '09 at 4:36 Unless I am wrong about Collection (as I said I can't test here) there should be an implicit Cast function on the collection.

There certainly is on a List – johnc Aug 26 '09 at 4:38.

What version of . Net are you using? If you are using .

Net 3.0+, you can only achieve this by using System.Linq. Check out this question, which solved it for me.

I am using . Net 2.0 – jameswelle Aug 26 '09 at 4:08.

You could use the Cast extension nails.Cast() I can't test it here to provide a more comprehensive example, as we are using . NET 2.0 at work (gripe gripe), but I did have a similar question here.

There is one solution that might not be quite what you are asking for but could be an acceptable alternative -- use arrays instead. Internal sealed class Bucket : IBucket { private Nail nails; INail IBucket. Nails { get { return this.

Nails; } } public Bucket() { this. Nails = new Nail100; } } (If you end up doing something like this, keep in mind this Framework Design Guidelines note: generally arrays shouldn't be exposed as properties, since they are typically copied before being returned to the caller and copying is an expensive operation to do inside an innocent property get. ).

Use this as the body of your property getter: List tempNails = new List(); foreach (Nail nail in nails) { tempNails. Add(nail); } ReadOnlyCollection readOnlyTempNails = new ReadOnlyCollection(tempNails); return readOnlyTempNails; That is a tad bit of a hacky solution but it does what you want. Edited to return a ReadOnlyCollection.

Make sure to update your types in IBucket and Bucket.

I think this is what I will have to do, but I will return a ReadOnlyCollection since adding to the returned collection won't affect the original. – jameswelle Aug 26 '09 at 4:32 There, fixed. – RCIX Aug 26 '09 at 4:43.

So I have my own (very simplistic) string collection interface. Note that my StringCollection class doesn't have to define the Count property because it inherits a perfectly good on from List. I have to manually copy the contents of the string collection a proper C++ standard container, but it works.

There may be a way to get proper type info from the standard collection classes, so you don't have to make your own collection interfaces, but if not, this should serve okay. Alternatively, have you looked at C++/CLI? That would work pretty seamlessly, although it still wouldn't convert CLR collections to std containers automatically.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions