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.

Pierre Arnaud
  • 9,402
  • 8
  • 70
  • 102
redb
  • 502
  • 7
  • 22
  • 10
    Could you post a short but complete program demonstrating the problem? – Jon Skeet Jun 27 '11 at 19:01
  • 1
    Yea, we can't really determine a problem without seeing some code. – MGZero Jun 27 '11 at 19:02
  • 7
    How could you use `typeof` on a type that doesn't exist at compile time? ***REALLY*** need to see some code here... – Marc Gravell Jun 27 '11 at 19:05
  • 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) – Mike Caron Jun 27 '11 at 19:08
  • @Marc: My guess is that a generic method is being called with reflection, and `typeof(T)` is being used within the generic method. – Jon Skeet Jun 27 '11 at 19:09
  • @Mike: If my guess to Marc is correct, it could well be a CLR bug rather than a compiler bug. – Jon Skeet Jun 27 '11 at 19:09
  • 1
    @Jon I actually mistyped CLR before correcting it to Compiler :P Still, you are correct in that we need to see teh codez – Mike Caron Jun 27 '11 at 19:11
  • @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(...)' – redb Jun 27 '11 at 19:24
  • @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)` – Marc Gravell Jun 27 '11 at 19:46
  • @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 ;-) – redb Jun 27 '11 at 19:57
  • 2
    @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. – Eric Lippert Jun 27 '11 at 20:43
  • @Eric to be fair, we had limited info to go on, if you see the [original few versions](http://stackoverflow.com/posts/6497570/revisions) – Marc Gravell Jun 27 '11 at 21:00
  • @Marc: Absolutely! I was very confused by this question at first as well. – Eric Lippert Jun 27 '11 at 21:12

2 Answers2

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.

Eric Lippert
  • 612,321
  • 166
  • 1,175
  • 2,033
  • I've come across the same kind of behaviour where VS.NET immediate window fed with `typeof(T)` returns `null` in a generic `Foo()` method. Eric: do you want access to the source code? – Pierre Arnaud Jun 20 '16 at 04:30
  • @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! – Eric Lippert Jun 20 '16 at 05:33
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
Mike Caron
  • 13,733
  • 4
  • 46
  • 74
  • 1
    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. – redb Jun 27 '11 at 19:35
  • 1
    `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. – Mike Caron Jun 27 '11 at 19:42
  • @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. – redb Jun 27 '11 at 19:51
  • 1
    @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. – Eric Lippert Jun 27 '11 at 19:54
  • 2
    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_. – Mike Caron Jun 27 '11 at 19:55
  • 3
    @Mike: Your "no exceptions" statement is not strictly speaking accurate. Suppose you created a type at compile time, C, and then created a type X at runtime, and then used reflection to create an instance of C. If C 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. – Eric Lippert Jun 27 '11 at 20:03
  • @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. – Mike Caron Jun 27 '11 at 20:09
  • @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]http://www.facebook.com/photo.php?fbid=184913271565869&set=a.184913231565873.49543.100001415919702&type=1 kinda states the opposite of that. I'm getting puzzled/confused. – redb Jun 27 '11 at 20:09
  • @Ricardo, since I can't look at Facebook, why don't you edit that into your question? – Mike Caron Jun 27 '11 at 20:10
  • 1
    @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. – Eric Lippert Jun 27 '11 at 20:12
  • @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) – redb Jun 27 '11 at 20:13
  • @Ricardo: Ah, for that, see Eric's last comment before you mentioned the Facebook link. Edit: and also my updated answer. – Mike Caron Jun 27 '11 at 20:15
  • @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. – redb Jun 27 '11 at 20:22
  • @Ricardo: If you edit your question, you should have a button for adding the picture that will upload it to imgur. – Joel B Fant Jun 27 '11 at 20:26
  • @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. – Joel B Fant Jun 27 '11 at 20:28
  • @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. – redb Jun 27 '11 at 20:33
  • @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 fact** – Mike Caron Jun 27 '11 at 20:36
  • @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. – Eric Lippert Jun 27 '11 at 20:39
  • 1
    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. :) – Joel B Fant Jun 27 '11 at 20:46
  • 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! – Mike Caron Jun 27 '11 at 20:50