views:

683

answers:

5

I have an object that I ended up with via a reflection call:

object readOnlyCollectionObject = propertyInfo.GetValue(someEntity, null);

I know this object is a generic ReadOnlycollection. It could be a ReadOnlyCollection<Cat>, ReadOnlyCollection<Dog>, etc. For argument sake, lets just say it is a ReadOnlyCollection<T>.

Even though a Dog derives from an object, I know that a ReadOnlyCollection<Dog> does not derive from a ReadOnlyCollection<object>. So even if I use reflection to call the CopyTo method I still need to know the specific type of ReadOnlyCollection, which is what I want to avoid.

I want to know how to get all the elements out of the ReadOnlyCollection as an array of object references without having to know the specific type (T) of the ReadOnlyCollection<T>.

+3  A: 

Well, you can use the Cast extension method on the readonly collection and then convert it to an array of objects but, based on the fact that in c# arrays are covariant, you can simply do:

object[] objs = myReadOnlyCollection.ToArray();

(edit)

As Pop Catalin mentioned, the only works if T is a reference type. Use the Cast method otherwise.

(edit2)

Your update to the question changes things quite a bit ... I think that what you're trying to do is not possible. You want to cast to a explicit Type at compile time that is only available at runtime. In this case, the only way you have to access the collection is with reflection.

bruno conde
Arrays of reference types are covariant, this will only work if T is a reference type.
Pop Catalin
Please have another look. I updated the description to show how I obtained this object.
hkdk3107
humm. This changes things quite a bit. See my second update.
bruno conde
Thanks Bruno. I will "Invoke" my way out of it :)
hkdk3107
+1  A: 
 var myArray = readOnlyCollection.Cast<object>().ToArray();
A: 

Do you want a deep clone of the collection? If you want to deep clone try this code below for memory deep cloning:

// deep copy in separeate memory space
public object Clone()
{
    MemoryStream ms = new MemoryStream();
    BinaryFormatter bf = new BinaryFormatter();
    bf.Serialize(ms, this);
    ms.Position = 0;
    object obj = bf.Deserialize(ms);
    ms.Close();
    return obj;
}
Patrick Peters
A: 

Cast your collection to a list of objects, then call ToArray():

ReadOnlyCollection<string> s;
object[] o = s.Cast<object>().ToArray();

Works only in C# 3.5 because of the extension methods.

Gerrie Schenck
+2  A: 

Many other answers mention Cast() and ToArray, those all have a problem with the type. As you say, you won't know which specialized IEnumerable your property will implement. However, you can be sure that they will all implement the non-generic ICollection interface.

ICollection readOnlyCollectionObject = (ICollection)propertyInfo.GetValue(someEntity, null);
object[] objs = new ArrayList(readOnlyCollectionObject).ToArray();

or

ICollection readOnlyCollectionObject = (ICollection)propertyInfo.GetValue(someEntity, null);
object[] objs = new object[readOnlyCollectionObject.Count];
for (int i = 0; i < readOnlyCollectionObject.Count; i++)
    objs[i] = readOnlyCollectionObject[i];

Edit: Forgot to update the cast from IEnumerable to ICollection

erikkallen
Problem is the first line won't compile because you cannot convert from IEnumerable to ICollection.
hkdk3107
Changed. Must have been a hard-to-spot typo.
erikkallen
This solution is very neat because it does not care about generics at all.
hkdk3107