【问题标题】:GetType returns diffent information than is operator usesGetType 返回的信息与操作员使用的不同
【发布时间】:2011-04-20 03:50:55
【问题描述】:

无法解释以下程序发生了什么。 GetType 正在返回我想要返回的类型,而不是原始类型。这是否意味着我们不能依赖 GetType? is 运算符是正确的。谁能详细解释一下?

using System;

namespace ConsoleApplication2
{
    public class MyClass
    {
        public Type GetType()
        {
            return typeof(Program);
        }

    }

class Program
{
    static void Main(string[] args)
    {
        MyClass mc = new MyClass();

        if (mc.GetType() == typeof(Program))
        {
            Console.WriteLine("Confused."); 
        }
        if(mc is Program)
        {
            Console.WriteLine(mc.GetType()); // Don't get inside the if. Why?
        }

    }
}
}

更新:我正在阅读《CLR via C# 3rd edition》一书。在第 4 章(第 2 页)中,当它解释 System.Object 中的不同方法时,它说

"GetType 方法是非虚拟的, 这可以防止一个类覆盖这个 方法并对其类型撒谎”

虽然我同意第一个陈述,但我在 MyClass 类型上撒谎。我不是吗?

【问题讨论】:

  • 你能确认这里的混淆是 mc.GetType() == typeof(Program) 实际上计算为 true 吗?
  • 是的。实际上,操作员似乎使用了一些与 GetType() 不同的机制来检查类型。如果是,机制是什么?上面的程序还表明我们不能相信 GetType 会返回正确的类型。
  • 我认为您对创建new 方法(隐藏祖先方法)和覆盖 祖先方法之间的区别感到困惑。 Eric Lippert 最近有a blog article 涉及到这一点(可能还有其他人,但这是我能找到的第一个)。阅读它可能会帮助您了解这里发生了什么。
  • 我明白发生了什么。但我的问题 1. 为什么 'is' 运算符不使用 GetType?如果答案是 GetType(当直接在对象上调用而不像 ((object)mc).GetType() 时)不能保证返回正确的类型,那么 GetType 在我们的代码中的用途是什么。这是否意味着在任何依赖 GetType 获取未知对象的代码中都可以被愚弄?

标签: c# clr


【解决方案1】:

is operator implemented in terms of as operator 最后使用isinst IL 指令。当然,这条指令不知道您在继承层次结构中的某个类中定义的非虚拟 GetType 方法。

要理解这种“令人困惑”的行为,让我们“实现”我们自己的“is 运算符”版本:

public class MyClass
{
    public Type GetType()
    {
        return typeof(Program);
    }

}

class Program {

    //this is oversimplified implementation,
    //but I want to show the main differences
    public static bool IsInstOf(object o, Type t)
    {
        //calling GetType on System.Object
        return o.GetType().IsAssignableFrom(t);
    }

    static void Main(string[] args)
    {
        MyClass mc = new MyClass();

        //calling MyClass non-virtual version for GetType method
        if (mc.GetType() == typeof(Program))
        {
            //Yep, this condition is true
            Console.WriteLine("Not surprised!");
        }

        //Calling System.Object non-virtual version for GetType method
        if (IsInstOf(mc, typeof(Program)))
        {
            //Nope, this condition isn't met!
            //because mc.GetType() != ((object)mc).GetType()!
        }

        Console.ReadLine();
    }            
}

【讨论】:

    【解决方案2】:

    请注意警告,因为它们的存在是有原因的。您的代码编译时出现以下警告:

    Warning 1 'ConsoleApplication2.MyClass.GetType()' hides inherited member 'object.GetType()'. Use the new keyword if hiding was intended.

    这意味着GetType() 是非虚拟的,并且您正在编写新的不相关的GetType() 方法,CLR 永远不会调用它。

    【讨论】:

    • 如果我的问题没有说清楚,我很抱歉。它与学术/理论兴趣有关,而不是使用最佳实践编写生产代码。
    【解决方案3】:

    Object.GetType 不是虚方法。所以mc is MyClass 并有效地调用Object.GetType 而不是你的方法。

    【讨论】:

    • 它(是操作员)是怎么做的?它是否首先将 mc 转换为对象,然后调用 GetType 方法?另请参阅我的问题的更新。虽然我们可以依赖“是”,但我们不能直接依赖 GetType。
    • 我相信 is 运算符归结为 CLR 中的 isinst 指令。我不知道这是如何实现的,但它可能会参考类似于 GetType 的对象表。结果与使用((object)mc).GetType() 测试的结果相同。
    【解决方案4】:

    is 检查变量的实际运行时类型。编译器并不关心您是否定义了一个名为 GetType() 的方法,该方法返回另一个 Type。它仍然知道你的变量的实际类型是MyClass

    您究竟想在这里完成什么?为什么你需要你的MyClass 类来模拟Program 类?

    【讨论】:

      【解决方案5】:

      根据文档,'is' 运算符不可重载。这就是为什么它可能没有进入您的第二个“if”语句。

      从 MSDN 查看此页面: http://msdn.microsoft.com/en-us/library/8edha89s%28v=VS.80%29.aspx

      【讨论】:

        【解决方案6】:

        只有在以下情况下才会正确:

        if (mc is MyClass) { ... }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-04-19
          • 2012-09-10
          • 2013-05-30
          • 1970-01-01
          相关资源
          最近更新 更多