alex
alex

Reputation: 1278

How to cast a object to IList<T> with unknown type T


I have a object[] containig some values. I want to extract infomation out of it, but I fail at casting the second object in the array (a WeakReference) to a IList with T as the third value in the array.

Take a look at my code:

object[] vals = GetValues(); //vals[2] = WeakReference, vals[3] = Type of T, vals[4] = index in the list
IList<((Type)vals[3])> list = (IList<((Type)vals[3])>)(((WeakReference)vals[2]).Target); //This line does not even compile, seems like I'm doing something wrong..
object oo = list.ElementAt((int)vals[4]);
//Do something with oo...

Any suggestions how I can cast the Target of the WeakReference to a IList interface with T = vals[3] ?

Upvotes: 4

Views: 8158

Answers (4)

Simon Mourier
Simon Mourier

Reputation: 138950

If you just need the object from an enumerable, at a given index, here is a simple function that does it:

    public static object GetObjectAt(IEnumerable enumerable, int index)
    {
        int i = 0;
        foreach (object obj in enumerable)
        {
            if (i == index)
                return obj;

            i++;
        }
        throw new IndexOutOfRangeException();
    }

And in your case, you would do this:

        object oo = GetObjectAt((IEnumerable)(WeakReference)vals[2], (int)vals[4]);

Of course there are alternatives that look more sexy (see other answers), with fancy linq queries and cool C# 4 dynamic new trendy stuff :-) but, in general, if you don't "need" the T type (in your example code, you don't need it), you don't need generics. This solution is actually supported with any .NET Framework and C# versions, from 1 to 4.

Upvotes: 2

Ani
Ani

Reputation: 113412

It's really strange that you are packing so much heterogeneous information into an array. Arrays are normally used to store elements of the same type. Why not encapsulate the data in a proper type?

But to answer the question as asked - in C# 4, you can use dynamic:

var target = ((dynamic)vals[2]).Target;

if(target != null)
{
    object oo = Enumerable.ElementAt(target, vals[4]);
    //Do something with oo...
}

(EDIT: If you want to minimize the use of dynamic here, cast to a WeakReference and leave the dynamic call to the end. This way, type-safety is 'maximized'.)

Otherwise, you can use reflection:

object target = ((WeakReference)vals[2]).Target;

if (target != null)
{
    object oo = target.GetType()
                      .GetProperty("Item")
                      .GetValue(target, new[] { vals[4] });
    //Do something with oo...
}

(EDIT: If the indexer could be explicitly implemented, you'll probably need to use the interface mappings.)

Upvotes: 5

Timwi
Timwi

Reputation: 66573

It was already suggested that you could use dynamic, but it sounds like you are also supposed to check that the object has the specified type. I’ve also kept use of dynamic to a minimum:

object target = ((WeakReference) vals[2]).Target;

if (target == null)
    throw new InvalidOperationException("Target cannot be null.");

object result = Enumerable.ElementAt((dynamic) target, (int) vals[4]);

if (result != null && !((Type) vals[3]).IsAssignableFrom(result.GetType()))
    throw new InvalidOperationException(string.Format("The retrieved object is a {0}, but the expected type was {1}.", result.GetType(), (Type) vals[3]));

return result;

Upvotes: 2

tvanfosson
tvanfosson

Reputation: 532505

I think you're working too hard to be able to use the extension methods which don't seem to be necessary.

object[] vals = GetValues();
var list = ((WeakReference)vals[2]).Target as IList;
object oo = null;
if (list != null)
{
    oo = list[(int)vals[4]];
}

Upvotes: 1

Related Questions