Будет ли этот код правильно определять, являются ли два типа равными?

Я немного запутался в System.Type сравнению с реальным типом класса (например, Object или XmlDocument) в .NET... будет ли этот код правильно определять, совпадает ли тип определенного объекта с классом, который я указываю?

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

If myObject.GetType.Equals(MyClass)

If TypeOf(myObject) Is MyClass

If myObject.GetType() Is MyClass

Который правильный?

Бонусные баллы, если вы можете предоставить некоторую информацию о том, что такое идентификатор класса по сравнению с System.Type. :)

Примечание: язык здесь не имеет значения, VB.NET или С# в порядке, код выше - псевдокод.

Ответы

Ответ 1

Сначала рассмотрим три варианта, которые вы дали:

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, который возвращает true, если myObject может быть приведен к MyClass. Это отличается от того, чтобы сказать, что это экземпляр этого типа, потому что может случиться так, что 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);
    
  • На экземпляре объекта вы можете получить метаданные System.Type, вызвав для него метод GetType(). Это даст вам экземпляр System.Type связанный с классом, который представляет фактический экземпляр. Это означает, что если ваш объект обрабатывается компилятором как интерфейс или базовый класс, .GetType() прежнему дает вам наиболее производный тип для этого экземпляра.

  • Вы можете сравнить System.Type, чтобы проверить, являются ли два объекта экземплярами одного и того же класса, но опять же, имейте в виду, что ваш экземпляр может иметь более производный тип; Равенство не удастся (тип System.Type более производного класса отличается от класса менее производного).

  • Если вам нужно принять во внимание наследование, вы можете использовать метод IsAssignableFrom, например:

    BaseClass instance = new DerivedClass();
    
    System.Type type = instance.GetType();
    
    if ((typeof(BaseClass)).IsAssignableFrom(type))    // returns true
    {
    }
    
  • С# и 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 не выполняет надлежащую проверку результатов; Проблема в том, что если вы не проверяете его на null и не используете его, вы получаете NullReferenceException, которое скроет правильную проблему (приведение не выполнено). Если вы уверены, что можете выполнить приведение, используйте явное приведение:

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

    Это вызовет InvalidCastException, поэтому код будет легче отлаживать.

Ответ 2

Подход .GetType() может завершиться неудачно, если элемент имеет значение null, поэтому сначала вам может потребоваться нулевая проверка.

Я не знаю о VB, но в С# вы используете is с объектом, а не с типом - i.e.

if(obj is MyClass) {...}

Другое отличие между is (сделано правильно) и GetType()/Equals - разница здесь - это подклассы. Если элемент на самом деле является SuperMyClass (унаследован от MyClass), то Equals или == вернет false - однако is вернет true.

typeof ограничивается использованием типов, а не переменных - т.е. typeof(MyClass), но не typeof(obj). Если вам нужен фактический тип объекта в переменной, используйте obj.GetType().

Лично я бы использовал (в С#):

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

так как это проверяет тип и бросает один раз, а не дважды

Ответ 3

Подводя итог, is сделает true для класса и подкласса. Например:

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