【问题标题】:typeof(T) may return nulltypeof(T) 可能返回 null
【发布时间】:2011-09-23 18:20:15
【问题描述】:

在通过 TypeBuilder 创建的类型上使用 typeof 运算符时,该运算符将返回 null。

我很好奇为什么会发生这种情况以及如何预防。


我开始认为这是即时窗口中的 VS 错误,但我不太确定。 先责备别人很容易。

好的...重现问题的代码:

    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);
    }

如果你在变量o 之后放置一个断点并在VS 即时窗口中键入typeof(MyType),你就会遇到问题。

【问题讨论】:

  • 您能否发布一个简短但完整的程序来演示该问题?
  • 是的,如果不查看一些代码,我们无法真正确定问题。
  • 如何在编译时不存在的类型上使用typeof真的需要在这里查看一些代码...
  • @Jon 我实际上在将 CLR 更正为编译器之前打错了:P 不过,您是正确的,因为我们需要查看 codez
  • @Marc:问题是你和里卡多正在互相交谈;他说的是运行时表达式求值器中 typeof 运算符的行为,而您说的是编译代码中 typeof 的行为。这是两个截然不同的子系统,它们使用 CLR 的不同部分。 Ricardo 显然在运行时表达式求值器中发现了一个奇怪的地方。在只执行静态分析的编译器版本的运算符中肯定不会发现类似的奇怪之处。

标签: c# clr clr4.0


【解决方案1】:

对通过TypeBuilder创建的类型使用typeof运算符时,该运算符将返回null。

首先,声明是正确的。如果你编写这个程序然后在调试器中停止它并在即时窗口中说“typeof(MyType)”,返回的结果是“null”。

我很好奇为什么会这样

让我大吃一惊。如果我不得不猜测,我会说表达式评估器可能正在与 CLR 的调试子系统通信,以尝试通过其名称获取类型的元数据令牌,而 CLR 正在返回一些垃圾 nil 令牌而不是产生错误.

我赶紧强调这是一个猜测;我还没有真正调试过。

我开始认为这是即时窗口中的 VS 错误

这似乎很有可能。它应该做的正确事情是给出错误“类型或命名空间'MyType'在此范围内无效”。该错误几乎肯定会出现在 C# 运行时表达式求值器中,而不是即时窗口本身。

感谢您提请我注意这个问题。我将向表达式评估器维护者提交一个错误,我们将看看他们是否可以解决这个问题。

如何预防?

如果键入“typeof(MyType)”时感到疼痛,请停止键入。

【讨论】:

  • 我遇到过同样的行为,即用typeof(T) 提供的VS.NET 即时窗口在通用Foo<T>() 方法中返回null。 Eric:你想访问源代码吗?
  • @PierreArnaud:我从 2012 年起就没有在 Microsoft 工作过。如果这个问题给您带来了困难,我建议您与 Visual Studio 团队的某个人一起讨论。祝你好运!
【解决方案2】:

如果您在变量 'o' 之后放置断点并在 VS Immediate Windows 中键入 typeof(MyType) 就会遇到问题。

嗯,是的。 MyType 没有符号(您正在使用反射定义它!),因此您不能在其上使用 typeof

编辑:为澄清起见,您可以使用typeof 并获得运行时创建的类型:当您使用泛型时。

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

【讨论】:

  • 嗯...为什么我需要符号?我只需要元数据。如果你这样做 o.GetType() 它会工作,但 typeof(MyType) 不会。我不认为符号在这种情况下会起作用。如果这是真的,则不可能在任何缺少其符号的程序集中使用 typeof,但事实并非如此。
  • typeof 是一种编译器结构,而不是 .NET 结构。它解析了编译时发生为名称的字符集,并将它们转换为它们所代表的System.Type。然而,System.Object.GetType() 是一个运行时概念,它直接返回 Type,无需花哨的编译器工作。
  • @Ricardo:迈克是对的。 “typeof”的意思是“嘿,编译器,这是一个字符串,它是你知道的类型的名称。它是什么类型?”您的类型是在运行时创建的;编译器对此一无所知。如果要获取动态创建类型的类型对象,请向类型构建器索取;这就是为什么它被称为类型生成器。
  • 让我换个说法。 typeof only 适用于编译时存在的类型。时期。没有例外。尝试将typeof(MyType) 放入您的代码中,看看会发生什么。编辑:@Eric 所说的。如果HE说是这样,就是这样
  • @Mike:严格来说,您的“无例外”声明并不准确。假设您在编译时创建了一个类型 C,然后在运行时创建了一个类型 X,然后使用反射创建了一个 C 的实例。如果 C 中有生成 typeof(T) 的代码,那么生成的代码应该能够返回 X 的类型对象。但在 表达式 的实际文本中,“typeof (T)",“T”必须是编译时已知的东西。这可以是在运行时解析的类型参数,但它必须是编译器知道的某事
猜你喜欢
  • 2012-09-23
  • 1970-01-01
  • 1970-01-01
  • 2020-10-02
  • 1970-01-01
  • 2011-01-16
  • 2019-06-25
  • 1970-01-01
相关资源
最近更新 更多