typeof(T) may return null
Asked Answered
M

2

9

When using the typeof operator on type created through TypeBuilder, the operator will return null.

I'm curious why this happens and how to prevent it.


I'm starting to think this is a VS bug in the immediate window, but I'm not quite sure. It's very easy to blame others first.

Ok... code to reproduce issue:

    static void Main()
    {
        AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
            new AssemblyName("MyAssembly"),
            AssemblyBuilderAccess.RunAndSave);
        ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MyModule");
        TypeBuilder typeBuilder = moduleBuilder.DefineType("MyType", TypeAttributes.Public, typeof(ArrayList));

        ArrayList o = (ArrayList)Activator.CreateInstance(typeBuilder.CreateType());

        Console.WriteLine(o.GetType().Name);
    }

If you put a breakpoint after the variable o and type typeof(MyType) in the VS Immediate Windows you'll get the issue.

Mert answered 27/6, 2011 at 18:58 Comment(13)
Could you post a short but complete program demonstrating the problem?Outgrow
Yea, we can't really determine a problem without seeing some code.Roxannaroxanne
How could you use typeof on a type that doesn't exist at compile time? REALLY need to see some code here...Cookery
If this is actually a thing (I doubt it is), it's a compiler bug. (but, since I doubt this is a thing, I'm not sure what the OP is going on about)Neelyneeoma
@Marc: My guess is that a generic method is being called with reflection, and typeof(T) is being used within the generic method.Outgrow
@Mike: If my guess to Marc is correct, it could well be a CLR bug rather than a compiler bug.Outgrow
@Jon I actually mistyped CLR before correcting it to Compiler :P Still, you are correct in that we need to see teh codezNeelyneeoma
@Mark typeof is not a compile time thing, if you look at the IL you'll see that under the covers it calls 'System.Type::GetTypeFromHandle(...)'Mert
@Ricardo - however, typeof() is a static analysis thing. It doesn't exist as far as the compiler exists. If you want a Type, use yourAssembly.GetType(fullName)Cookery
@Mike... Well the thing is that... well... don't want to be rude, but that is not true. There is nothing 'static' about the typeof. (It looks like it, but it isn't, I can show you code that states otherwise) But I may be wrong... If so, please prove me wrong, I actually love to learn about the Clr internals ;-)Mert
@Marc: The thing is that you and Ricardo are talking past one another; he's talking about the behaviour of the typeof operator in the runtime expression evaluator, and you're talking about the behaviour of typeof in compiled code. Those are two extremely different subsystems that use very different parts of the CLR. Ricardo has apparently found an oddity in the runtime expression evaluator; a similar oddity will certainly not be found in the compiler's version of the operator, which only performs static analysis.Antoinetteanton
@Eric to be fair, we had limited info to go on, if you see the original few versionsCookery
@Marc: Absolutely! I was very confused by this question at first as well.Antoinetteanton
A
21

When using the typeof operator on type created through TypeBuilder, the operator will return null.

First of all, the claim is correct. If you write this program and then stop it in the debugger and say "typeof(MyType)" in the immediate window, the result that comes back is "null".

I'm curious why this happens

Beats the heck out of me. If I had to guess, I'd say that maybe the expression evaluator is communicating with the CLR's debugging subsystem to try and get a metadata token for the type by its name, and the CLR is returning some garbage nil token rather than producing an error.

I hasten to emphasize that this is a guess; I have not actually debugged it.

I'm starting to think this is a VS bug in the immediate window

That seems likely. The correct thing that it should be doing is giving the error "the type or namespace 'MyType' is not valid in this scope". The bug will almost certainly be in the C# runtime expression evaluator, not in the immediate window itself.

Thanks for bringing the issue to my attention. I'll file a bug with the expression evaluator maintainers and we'll see if they can address the issue.

how to prevent it?

If it hurts when you type "typeof(MyType)" then stop typing that.

Antoinetteanton answered 27/6, 2011 at 20:35 Comment(2)
I've come across the same kind of behaviour where VS.NET immediate window fed with typeof(T) returns null in a generic Foo<T>() method. Eric: do you want access to the source code?Ichthyosis
@PierreArnaud: I haven't worked for Microsoft since 2012. I suggest you take it up with someone on the Visual Studio team if this problem is causing you difficulties. Good luck!Antoinetteanton
N
6

If you put a breakpoint after the variable 'o' and type typeof(MyType) in the VS Immediate Windows you'll get the issue.

Well, yeah. MyType doesn't have a symbol (you're defining it using reflection!), so you can't use typeof on it.

Edit: For clarification, there is exactly one time where you can use typeof and get a runtime-created type: When you're using generics.

Type MyMethod<T>() where T : class {
    return typeof(T);
}

Type myType = //create type dynamically;

Type myOtherType = //invoke MyMethod with myType as the type parameter

Debug.Assert(myType == myOtherType); //will not fire
Neelyneeoma answered 27/6, 2011 at 19:22 Comment(20)
Hummm... Why do I need symbols? I only need the metadata. If you do o.GetType() it will work but typeof(MyType) won't. I don't think symbols come to play in this situation. If that were true it would be impossible to use typeof in any assembly missing its symbols, which is not the case.Mert
typeof is a compiler construct, not a .NET one. It resolves the compile time clump of characters that happen to be a name, and turns them into the System.Type that they represent. System.Object.GetType(), however, is a runtime concept that returns the Type directly, without having to fancy compiler work.Neelyneeoma
@Mike Completly true Mike, but... It still doesn't explain the behavior nor it should, nor how to circumvent it, I believe it's some sort of bug or 'by design'. Because... Well... the typeof operator works quite fine, I'm only having this behavior in the Immediate Window.Mert
@Ricardo: Mike is right. "typeof" means "hey, compiler, here's a string that is the name of a type that you know about. What type is it?" Your type is created at runtime; the compiler knows nothing about it. If you want to get a type object for a dynamically created type, ask the type builder for it; that's why its called a type builder.Antoinetteanton
Let me rephrase. typeof only works on types that exist at compile time. Period. No exceptions. Try putting typeof(MyType) in your code, and see what happens. Edit: what @Eric said. If HE says it's so, it's friggin so.Neelyneeoma
@Mike: Your "no exceptions" statement is not strictly speaking accurate. Suppose you created a type at compile time, C<T>, and then created a type X at runtime, and then used reflection to create an instance of C<X>. If C<T> has code in it that generates typeof(T), then the generated code ought to be able to return the type object for X. But in the actual text of the expression, "typeof(T)", the "T" has to be something that is known at compile time. That can be a type parameter resolved at runtime, but it has to be something known to the compiler.Antoinetteanton
@Eric, technically, the T is what's known at compile time, right? Well, I suppose my statement is still invalid, since T is not a type. However, the point still remains.Neelyneeoma
@Eric I don't wan't to "fight" the great Eric Lipper, (And I say this with a great sense of admiration), but... this picture [link]facebook.com/… kinda states the opposite of that. I'm getting puzzled/confused.Mert
@Ricardo, since I can't look at Facebook, why don't you edit that into your question?Neelyneeoma
@Ricardo: Nobody is fighting -- we're just trying to understand the claim you're making here. Regardless though, if what you want is the type object of a dynamically generated type, then don't use typeof; you already have the type object in hand so you don't need to get it by name.Antoinetteanton
@Mike, I don't have anywhere else where to put the picture, basically it's a screenshot of the code running and I'm printing using typeof(T) where T is actually MyType, (created in memory)Mert
@Ricardo: Ah, for that, see Eric's last comment before you mentioned the Facebook link. Edit: and also my updated answer.Neelyneeoma
@Eric I meant "fighting" in a non literal way :), I meant... it's hard to make a point with someone that has tons of knowledge about the compiler internals. Nonetheless I want to understand why the Immediate Window fails and way it doesn't fail in actual code. Basically you're stating a behavior about the the Clr/Compiler that I'm not experiencing, actually quite the opposite.Mert
@Ricardo: If you edit your question, you should have a button for adding the picture that will upload it to imgur.Dimaggio
@Ricardo: And the image shows you doing typeof(T). Maybe if you did typeof(T) in the immediate window after stopping at a breakpoint in a generic function, it would work right.Dimaggio
@Joel unfortunately I don't have enough Stackoverflow reputation to post a picture. :( In any case doing typeof(T) or typeof(MyType) is the same thing... But just for the sake of the argument I did it, and the behavior maintains as expected.Mert
@Ricardo: T is defined at compile time, MyType is not. If you ask what type T is, the compiler will emit code at runtime to look it up. If you ask what type MyType is, it will throw an error since it doesn't know what MyType is. typeof is 100% compiler implemented, and has no meaning after the factNeelyneeoma
@Mike: Sure, but again, let's hold up a minute here. The question is not actually about what happens when you type "typeof(T)" into a C# program and then compile it. The question is about what happens when you type "typeof(T)" into the debugger's immediate window. That thing does not have to obey the rules of C#, and in fact, breaks them all the time. It has to, because you need to be able to evaluate expressions that involve private members and so on. There are all kinds of ways in which the immediate window code semantics differ from C# code semantics, and Ricardo seems to have found one.Antoinetteanton
I invoked a generic method via reflection with the right type parameter (from typeBuilder.CreateType()) and set a breakpoint in the generic method. typeof(T) in the generic method worked ok and typeof(T) in the immediate window returns null. So like Eric says, the immediate window is different. :)Dimaggio
Well, I'll be darned. Since I couldn't see the OP's picture, I assumed he had typeof(T) inside the method, not the Immediate window. Shows what I get for making assumptions!Neelyneeoma

© 2022 - 2024 — McMap. All rights reserved.