Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will this code correctly determine if two types are equal?

I'm a little foggy on System.Type versus an actual class type (like Object or XmlDocument) in .NET... will this code correctly determine if the type of a particular object is equal to a class I specify?

' 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

Which one is correct?

Bonus points if you can provide some information on what a class identifier is versus what a System.Type is. :)

Note: The language doesn't matter here, VB.NET or C# is fine, the code above is pseudocode.

like image 633
qJake Avatar asked May 20 '11 14:05

qJake


People also ask

How to check if 2 types are equal c#?

Equals() Method. Type. Equals() Method is used to check whether the underlying system type of the current Type is the same as the underlying system type of the specified Object or Type.

Should I override equality and inequality operators?

In a class, if you overload the Equals method, you should overload the == and != operators, but it is not required. This code reports that p1 equals p2 despite the difference in z values. The difference is ignored because the compiler picks the TwoDPoint implementation of IEquatable based on the compile-time type.


2 Answers

Fist let's take a look on the three options you gave:

If myObject.GetType.Equals(MyClass)

This will probably result in a error, since the equals expects a System.Type, not a class. A class definition is not a System.Type, but you can retrieve it using the typeof operator. So you could do instance.Equals(typeof(MyClass)), which would return true if the object is of the given class.

If TypeOf(myObject) Is MyClass

Conversely, you can't use typeof with instances, only with classes, so the above code would fail. Also, the is operator automatically checks the typing so you can't do a typeof or a GetType when using it. You should go with if myObject is MyClass, which would return true if myObject can be cast to MyClass. This is different from saying that it's an instance of that type, because it could be that myObject is an instance of a class that inherits from MyClass.

If myObject.GetType() Is MyClass

Again, the is operator already checks the type on both operands, so you should go with if myObject is MyClass.


All that said, I'd like to explain the "theory" behind the type system. I'm no specialist, so I'm giving you a more practical explanation:

  • A class definition label (like MyClass) is not a System.Type. A System.Type is a metadata class that is generated by the CLR to represent the type defined by your label. To retrieve the System.Type related to a certain class definition label, use the typeof operator as follows:

    System.Type MyClassType = typeof(MyClass);
    
  • On a object instance, you can retrieve the System.Type metadata by calling the method GetType() on it. It will give you an instance of System.Type related to the class that represents the actual instance. This means that if your object is being treated by the compiler as a interface or a base class, .GetType() still gives you the most derived type for that instance.

  • You can compare System.Type in order to check if two objects are instances of the same class, but again, beware that your instance can be of a more derived type; The equality will fail (the System.Typeof a more derived class is different than that of a less derived one).

  • If you need to take inheritance into account, you can use the method IsAssignableFrom, like this:

    BaseClass instance = new DerivedClass();
    
    System.Type type = instance.GetType();
    
    if ((typeof(BaseClass)).IsAssignableFrom(type))    // returns true
    {
    }
    
  • C# and VB.Net gives you two operators that enables you to do type checking on the fly, is and as. is does automatic typing retrieval and is preferred over getting the System.Type yourself. It accounts for inheritance as well:

    DerivedClass instance = new DerivedClass();
    
    System.Type type = instance.GetType();
    
    if (instance is BaseClass)    // returns true
    {
    }
    
  • If you need to check the type and cast the object use 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
    }
    

    What you cannot do with as is not perform proper result checking; The problem is that if you don't check it for null and use it, you get an NullReferenceException, which will hide the correct problem (the cast failed). If you are sure you can do the cast, then use a explicit cast:

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

    This will throw an InvalidCastException, so the code will be easier to debug.

like image 128
Bruno Brant Avatar answered Sep 19 '22 09:09

Bruno Brant


The .GetType() approach could fail if the item is null, so you might want a null check first.

I don't know about VB, but in C# you use is with the object, not it's type - i.e.

if(obj is MyClass) {...}

Another difference between is (done correctly) and GetType()/Equals - the difference here is subclasses. If the item is actually an SuperMyClass (inherited from MyClass) then Equals or == will return false - however, is will return true.

typeof is restricted to use with types, not variables - i.e. typeof(MyClass), but not typeof(obj). If you want the actual type of an object in a variable, use obj.GetType().

Personally, I would use (in C#):

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

as this does a type-check and cast once rather than twice

like image 41
Marc Gravell Avatar answered Sep 19 '22 09:09

Marc Gravell