Поделиться через


Quiz of the month: Type.FullName

I once had a dev manager who loves puzzles and quizes. During our team meetings, he will write some code on the board and the team would have a competition to see who can spot the mistake first or who can answer a question about the code first. I always enjoyed those quiz. So I think I am going to start this on my blog. Once a month, I'll find something interesting and see who can give me the answer and an explaination why. :) Of course you can just run the code and have the right answers, but understanding why is the interesting part.

Here is my first "Quiz of the month"! I'll post the answer to this in 2 weeks.

Without running it, can you tell me whether the code below will assert? If yes, why? If not, why not?

    class Prog

    {

        static void Main(string[] args)

        {

            Type t1 = typeof(DerivedClass<>);

            Type t2 = t1.BaseType;

            string fullName1 = t1.FullName;

            string fullName2 = t2.FullName;

            Debug.Assert(fullName1 == fullName2);

        }

    }

    public class BaseClass<T>

    {

    }

    public class DerivedClass<T> : BaseClass<T>

    {

    }

Comments

  • Anonymous
    April 07, 2006
    I certainly look like it should.
    t1.FullName should return "DerivedClass" and t2.FulleName should return "BaseClass"
  • Anonymous
    April 07, 2006
    The comment has been removed
  • Anonymous
    April 08, 2006
    I'm not sure, Kathy, but just looking at that code it looks like there is a mistake, because there are one big reason why the assert wouldn't fire. t1 refers to something related to DerivedClass, while t2 refers to something related to BaseClass, so their FullNames couldn't be equal.

    The mistake, I think, is that you should have had code like this in Main:

               Type t1 = typeof(DerivedClass<>).BaseType;
               Type t2 = typeof(BaseClass<>);
               string fullName1 = t1.FullName;
               string fullName2 = t2.FullName;
               Debug.Assert(fullName1 == fullName2);

    This makes the question more interesting. Is the generic base type of a generic type the same as its generic base type's type? The answer is no.

    t1 refers to the base type of DerivedClass<>. However, DerivedClass<> takes a generic argument T, and inherits from BaseType<> specialized with this generic argument. Thus, the base type of DerivedClass<> is already specialized, and is no longer an open generic type willing to accept a generic argument. Its generic argument is already filled by DerivedClass<>'s T.

    t2 refers to the BaseType<>, which is an open generic type, and is willing to be called by MakeGenericType(), providing a type argument.

    Thus, the two types, t1 and t2, are different, so we shouldn't expect them to have the same FullNames.

    Type.FullName is expected to return a string that you can later pass to Type.GetType(), and retrieve the same type. That is, "Type.GetType(t.FullName) == t" should be true, where t is of type Type.

    It would appear that the CLR has no valid way of describing a generic type specialized by a generic type argument defined in a different class by way of inheritance. So, t1.FullName returns null, because Type.GetType() wouldn't be able to return the BaseType<> specialized with DerivedType<>'s T. Of course, getting such a BaseType<> specialization wouldn't be very useful, so that's ok.
  • Anonymous
    April 08, 2006
    Jared,

    That's probably not a bug, t2 could have been collected by then. Although, when compiling in debug that likely not to happen.
  • Anonymous
    April 09, 2006
    I suggest a possible solution: The type full name MUST guarantee that we can create a type ( also a generic one ) calling Type.GetType(string..). If we look to the BaseType property documentation we can read: "If the current Type represents a type parameter of a generic type definition, BaseType returns the class constraint, that is, the class the type parameter must inherit. If there is no class constraint, BaseType returns System.Object". In fact if we inspect t2 we will notice that it is not an IsGenericTypeDefinition=true but the "real" type BaseClass is. So we cannot create an instance  of t2 and this is the reason t2 will have a fullName value null that cause the program to assert.
    Please apologize me for my bad english.
  • Anonymous
    April 10, 2006
    The comment has been removed
  • Anonymous
    April 10, 2006
    Well, Hmm, this one is a little different.

    t1 should give the name of the derived class. complete with it's namespace.

    However I would expect t2 would be the string to the base type of t1 which is a Type Class hence doesn't have a type so it is null.

    I confirmed this by writing a little test code.
               Type t1 = typeof(DerivedClass<>);
               Type t2 = t1.BaseType;
               if (t2.FullName == null) Console.WriteLine ("Its null");
               string fullName1 = t1.FullName;
               string fullName2 = t2.FullName;
  • Anonymous
    April 11, 2006
    The answer is here:

    http://blogs.msdn.com/haibo_luo/archive/2006/02/17/534480.aspx
  • Anonymous
    April 16, 2006
    It is strange, that t2.FullName is null, but t2.ToString() returns "BaseClass`1[T]"
  • Anonymous
    June 15, 2009
    PingBack from http://einternetmarketingtools.info/story.php?id=21839