【问题标题】:Will this code correctly determine if two types are equal?此代码能否正确确定两种类型是否相等?
【发布时间】:2011-08-29 17:51:08
【问题描述】:

我对 System.Type 与 .NET 中的实际类类型(如 Object 或 XmlDocument)有点模糊......这段代码能否正确确定特定对象的类型是否等于我指定的类?

' Given "myObject" (unknown type), and some class type (let's say "MyClass")...

If myObject.GetType.Equals(MyClass)

If TypeOf(myObject) Is MyClass

If myObject.GetType() Is MyClass

哪个是正确的?

如果您能提供一些关于什么是类标识符与什么是System.Type 的信息,则可以加分。 :)

注意:这里语言无所谓,VB.NET或者C#都可以,上面的代码是伪代码。

【问题讨论】:

  • 我一直认为一个对象在技术上是一种类型,所有的类都是从一个对象继承而来的。

标签: c# .net vb.net types


【解决方案1】:

如果项目为空,.GetType() 方法可能会失败,因此您可能需要先进行空检查。

我不了解 VB,但在 C# 中,您使用带有 object 的 is,而不是它的类型 - 即

if(obj is MyClass) {...}

is(正确完成)和 GetType()/Equals 之间的另一个区别 - 这里的区别在于子类。如果项目实际上是 SuperMyClass(继承自 MyClass),则 Equals 或 == 将返回 false - 但是,is 将返回 true。

typeof 仅限于与 types 一起使用,而不是 variables - 即 typeof(MyClass),但不是 typeof(obj)。如果您想要变量中对象的实际类型,请使用obj.GetType()。

就个人而言,我会使用(在 C# 中):

var typed = obj as MyClass;
if(typed != null) {
    // do something interesting with typed
}

因为这会进行类型检查并强制转换一次而不是两次

【讨论】:

  • 如果我必须使用 System.Type,比如一个类是否包含 Type 类型的属性 - 我如何检查 Type 是否是一个特定类?我不能在 VB 中使用Is,它会报错。
  • 为了记录,VB 中的TypeOf 使用变量而不是类型。由于此问题也被标记为 VB,因此等效语法(无换行符)为 Dim typed = TryCast(obj, MyClass) If typed IsNot Nothing Then ...
【解决方案2】:

先来看看你给出的三个选项:

If myObject.GetType.Equals(MyClass)

这可能会导致错误,因为 equals 需要 System.Type,而不是类。类定义不是System.Type,但您可以使用typeof 运算符检索它。所以你可以做instance.Equals(typeof(MyClass)),如果对象属于给定的类,它会返回true。

If TypeOf(myObject) Is MyClass

相反,您不能将typeof 与实例一起使用,只能与类一起使用,因此上述代码会失败。此外,is 运算符会自动检查输入,因此您在使用时不能使用typeof 或GetType。你应该使用if myObject is MyClass,如果myObject 可以转换为MyClass,它将返回true。这与说它是该类型的实例不同,因为 myObject 可能是继承自 MyClass 的类的实例。

If myObject.GetType() Is MyClass

同样,is 运算符已经检查了两个操作数的类型,因此您应该使用 if myObject is MyClass。


说了这么多,我想解释一下类型系统背后的“理论”。我不是专家,所以我给你一个更实际的解释:

  • 类定义标签(如MyClass)不是System.Type。 System.Type 是由 CLR 生成的元数据类,用于表示标签定义的类型。要检索与某个类定义标签相关的System.Type,请使用typeof 运算符,如下所示:

    System.Type MyClassType = typeof(MyClass);
    
  • 在对象实例上,您可以通过在其上调用方法 GetType() 来检索 System.Type 元数据。它将为您提供与代表实际实例的类相关的System.Type 实例。这意味着,如果编译器将您的对象视为接口或基类,.GetType() 仍会为您提供该实例的最派生类型。

  • 您可以比较System.Type 以检查两个对象是否是同一类的实例,但同样要注意,您的实例可能是更派生的类型;等式将失败(派生程度较高的类的System.Type与派生程度较低的类不同)。

  • 如果需要考虑继承,可以使用IsAssignableFrom方法,如下:

    BaseClass instance = new DerivedClass();
    
    System.Type type = instance.GetType();
    
    if ((typeof(BaseClass)).IsAssignableFrom(type))    // returns true
    {
    }
    
  • C# 和 VB.Net 为您提供了两个运算符is 和as,使您能够即时进行类型检查。 is 进行自动输入检索,比自己获取 System.Type 更可取。它也解释了继承:

    DerivedClass instance = new DerivedClass();
    
    System.Type type = instance.GetType();
    
    if (instance is BaseClass)    // returns true
    {
    }
    
  • 如果您需要检查类型并投射对象,请使用as:

    DerivedClassinstance = new DerivedClass();
    
    System.Type type = instance.GetType();
    
    AnotherClass another = instance as AnotherClass;
    
    if (another == null)    // returns true
    {
        // Do proper error treatment... throw an exception or something
    }
    

    你不能用as做的不是执行正确的结果检查;问题是,如果你不检查它是否为空并使用它,你会得到一个NullReferenceException,它将隐藏正确的问题(转换失败)。如果您确定可以进行强制转换,请使用显式强制转换:

    DerivedClassinstance = new DerivedClass();
    
    System.Type type = instance.GetType();
    
    AnotherClass another = (AnotherClass)instance; // throws
    

    这会抛出一个InvalidCastException,所以代码会更容易调试。

【讨论】:

  • 虽然这个问题同时被标记为 C# 和 VB,但 OP 中的语法显然是 VB。这是关键字相似但做不同事情的领域之一。您对第一个 Equals(typeof(MyClass)) 的建议将无法编译,并且关于 typeof 用于类而不是实例的类似断言对于 VB 来说是倒退的。此外,VB 中的Is 运算符与C# 不同。在 VB 中,Is 执行引用比较,而不是类型检查。
  • @Gideon:OP 明确指出“这里的语言无关紧要,VB.NET 或 C# 都可以,上面的代码是伪代码。”所以我选择了 C#比较熟悉。
【解决方案3】:

综上所述,is 将适用于类和子类。例如:

class B:Program{}
class Program{}
Program a = new Program();
B b = new B();
if (b is Program) ; // true
if (a is Program) ; // true
if (a is B) ; // false
if (b is B) ; //false

并使用 Equals 和 typeof([ClassName]) 只是等于类,而不是子类:

class B:Program{}
class Program{}
Program a = new Program();
B b = new B();
if (b.GetType() == typeof(program)) ; // false
if (b.GetType() == typeof(B)) ; // true
if (a.GetType() == typeof(B)) ; // false
if (a.GetType() == typeof(Program)) ; //true

【讨论】:

  • 程序从何而来?它不是代码中声明的类型,因此会导致语法错误。你的意思是if (b.GetType() == typeof(Program)) ;吗?
猜你喜欢
  • 1970-01-01
  • 2020-02-25
  • 1970-01-01
  • 2010-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多