locked
getting the superclass of a generic type, and it's generic parameters.

    Question

  • Hey everyone,

     

    I Was wondering (never trust a person who starts a sentence with 'I'  ...) if any of you guys might show me the path on this one - and I do believe that my code will explain the problem better than words:

     

    Code Block

    using System;

    using System.Collections.Generic;

    using System.Text;

     

    namespace TestApp

    {

    class Program

    {

    class MyType

    {

    }

     

    class MyTypeInheritor : MyType<string>

    {

    }

     

    public class Consumer

    {

    public Consumer()

    {

    //Currently ...

    if (!(typeof(G).BaseType.Name == "MyType`1"))

    {

    //Report an Error

    }

     

    //Actually need to check:

    //"Does this instance inherit from 'FirstType' ?

    //"If so, since G is of the form FirstType, what exactly are T and S ?"

    }

    }

     

    static void Main(string[] args)

    {

    Consumer<MyTypeInheritor> MyConsumer = new Consumer<MyTypeInheritor>();

    }

    }

    }

     

     

     

    So, as you can see, I am currently checking for a superclass not so elegantly ... I was thinking of using the "is" keyword but encountered the following problem : To ask

     

    Code Block
    if (G is MyType<[What goes here ? ...]>)

     

     

    I need extra information.

     

    I commented the three lines that best describe my need.

    Probably reflection is the way to go here, and I would be happy for any direction you guys might have.

     

     

    Have a wonderfull week,

    Kobi.

    Saturday, October 13, 2007 4:33 PM

Answers

  • It seems like the issue you are struggling with is that "constructed" generic types, such as List<int>, do not inherit from their unconstructed generic type, which is represented such as List<>.  This can be seen by noting that you cannot cast List<int> to List<>.

     

    The following IsGeneric function may be of help.  For example, you could pass the Type to be tested as the first parameter and an unconstructed generic Type, such as typeof(List<>) as the second parameter to determine if first parameter (in consideration of all of its base classes) is any constructed type of the second parameter.

     

    You should ask yourself whether this is a good design.  It may be better to implement a non-generic interface on your base generic and then just test for that interface which is, of course, straightforward.  In the event that this interface would have no methods, it is better to use a custom attribute, which is likewise simple to implement.

     

    Code Block

    public static bool IsGeneric(Type t, Type genericTypeDefinition)

    {

    if (t == null)

    throw new ArgumentNullException("t");

    if (genericTypeDefinition == null)

    throw new ArgumentNullException("genericTypeDefinition");

    if (!genericTypeDefinition.IsGenericTypeDefinition)

    throw new ArgumentException("Must specify a generic type definition.", "genericTypeDefinition");

    while (t != null)

    {

    if (t.IsGenericType)

    {

    if (t.GetGenericTypeDefinition() == genericTypeDefinition)

    {

    return true;

    }

    }

    t = t.BaseType;

    }

    return false;

    }

     

     

    You also ask, "what exactly are T and S?"  Using the same loop as above, in place of the return true, you can do t.GetGenericArguments() to return those Types.

     

    Saturday, October 13, 2007 11:19 PM

All replies

  • It seems like the issue you are struggling with is that "constructed" generic types, such as List<int>, do not inherit from their unconstructed generic type, which is represented such as List<>.  This can be seen by noting that you cannot cast List<int> to List<>.

     

    The following IsGeneric function may be of help.  For example, you could pass the Type to be tested as the first parameter and an unconstructed generic Type, such as typeof(List<>) as the second parameter to determine if first parameter (in consideration of all of its base classes) is any constructed type of the second parameter.

     

    You should ask yourself whether this is a good design.  It may be better to implement a non-generic interface on your base generic and then just test for that interface which is, of course, straightforward.  In the event that this interface would have no methods, it is better to use a custom attribute, which is likewise simple to implement.

     

    Code Block

    public static bool IsGeneric(Type t, Type genericTypeDefinition)

    {

    if (t == null)

    throw new ArgumentNullException("t");

    if (genericTypeDefinition == null)

    throw new ArgumentNullException("genericTypeDefinition");

    if (!genericTypeDefinition.IsGenericTypeDefinition)

    throw new ArgumentException("Must specify a generic type definition.", "genericTypeDefinition");

    while (t != null)

    {

    if (t.IsGenericType)

    {

    if (t.GetGenericTypeDefinition() == genericTypeDefinition)

    {

    return true;

    }

    }

    t = t.BaseType;

    }

    return false;

    }

     

     

    You also ask, "what exactly are T and S?"  Using the same loop as above, in place of the return true, you can do t.GetGenericArguments() to return those Types.

     

    Saturday, October 13, 2007 11:19 PM
  • Hey,

     

    Thanks for the very quick reply. I think the recommendation of implementing a non-generic interface on the Base Type would do the trick. I marked your response as an answer to this post, and I hope it doesn't seem arrogant.

    The method you posted seems helpful, and I will adjust it to my needs. Thanks alot and hopefully I will return the favour soon .

     

    Kobi.

    Sunday, October 14, 2007 6:02 PM