The "is/as" operators and generic collections

C

CodePoetry

Hi there,

I have a piece of logic that reads properties of a type and looks for
properties that are collections of elements.

For instance, one of the properties of such object could be of type
PersonCollection which I derrive from List<Person>. Note that List<T>
implements IEnumerable<T>.

The code needs to determine if the type of the property is an implementation
of IEnumerable<T>. If it is, it would return the actual type of the objects,
rather than generic T. For example, if the type of the property is
PersonCollection, I need it to return type Person.

Is there a way to accomplish this?

Thanks.
 
A

Arne Vajhøj

I have a piece of logic that reads properties of a type and looks for
properties that are collections of elements.

For instance, one of the properties of such object could be of type
PersonCollection which I derrive from List<Person>. Note that List<T>
implements IEnumerable<T>.

The code needs to determine if the type of the property is an implementation
of IEnumerable<T>. If it is, it would return the actual type of the objects,
rather than generic T. For example, if the type of the property is
PersonCollection, I need it to return type Person.

Is there a way to accomplish this?

And the obvious:

using System;
using System.Collections.Generic;

namespace E
{
public class Person
{
}
public class PersonCollection : List<Person>
{
}
public class Program
{
public static void Main(string[] args)
{
PersonCollection pc = new PersonCollection();
if(pc is IEnumerable<Person>) Console.WriteLine("We have an
IEnumerable<Person>");
Console.ReadKey();
}
}
}

is not good enough because?

Arne
 
P

Peter Duniho

CodePoetry said:
Hi there,

I have a piece of logic that reads properties of a type and looks for
properties that are collections of elements.

For instance, one of the properties of such object could be of type
PersonCollection which I derrive from List<Person>. Note that List<T>
implements IEnumerable<T>.

The code needs to determine if the type of the property is an implementation
of IEnumerable<T>. If it is, it would return the actual type of the objects,
rather than generic T. For example, if the type of the property is
PersonCollection, I need it to return type Person.

Is there a way to accomplish this?

Unfortunately, it is not really clear what "this" is.

I'm pretty sure both of the other replies have missed the point. I
doubt you are simply asking for static typing of a specific, known
property. Rather, your post _seems_ to be related to some
reflection-based scenario you apparently have.

But even making that guess, your post does not provide enough
information to know exactly what it is you want.

Using reflection, you can inspect the type of the property, via the
PropertyInfo class. For example, if you are specifically looking for
IEnumerable<T>, you can first check the IsGenericType property of the
property's Type. If the type is generic, then you can call
GetGenericTypeDefinition() on the same Type object to get a new Type
object, when you can then compare with the generic type IEnumerable<T>.

(Note: the IsGeneric property only gives information for the immediate
type. If the property is actually of some different type that simply
implements or inherits IEnumerable<T> — as in your PersonCollection
example — and you still want to detect that, then you have to do more
work, checking the base types and/or implemented interfaces by calling
GetInterfaces() and examining the results of that).

Having done all that to identify a property that is in fact of type
IEnumerable<T> for some T, you can then call GetGenericArguments() to
retrieve the type T (using the instance of Type retrieved from whatever
call from which you identified the type as generic in the first
place…i.e. this could be the property's type itself, or one of the types
returned by GetInterfaces()) to identify what type the enumeration
elements are.

Of course, having done this, you would still presumably need to _do_
something with that type. It is that aspect of your question that is
the least clear, and yet is the most likely to cause trouble for you.
Retrieving type information via reflection (as above) is not very hard.
Doing something useful with that information can be, depending on what
it is you really want to do.

If you can explain more precisely how you expect to use this
information, a better answer can be provided.

Finally, I will make a suggestion unrelated to your actual question: it
has been my experience that inheriting the existing collection types is
almost always not useful. The types aren't really designed well for
inheritance, and so other than providing convenience methods which can
be done just as easily with extension methods, the inheritance doesn't
really gain you much.

I'm sure there are exceptions to this, but I've yet to see a real-world
case of inheriting an existing collection class where it really added
much, if any, value to the design of the code.

Pete
 
C

CodePoetry

Hi all,

Thanks everyone for responding. You were all helpful. Here's the solution I
came to using your responses. In the end, the elementType variable will have
typeof(Person), which is exactly what I'm looking for.

PersonCollection pc = new PersonCollection();
Type collectionType = pc.GetType();
var enumerableType = collectionType.GetInterfaces()
.Where(t => t.IsGenericType && t.GetGenericTypeDefinition()
== typeof(IEnumerable<>))
.FirstOrDefault();
if (enumerableType != null)
{
var elementType =
enumerableType.GetGenericArguments().First();
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top