Я видел, как многие люди используют следующий код:
Type t = typeof(obj1);
if (t == typeof(int))
// Some code here
Но я знаю, что вы также можете сделать это:
if (obj1.GetType() == typeof(int))
// Some code here
Или так:
if (obj1 is int)
// Some code here
Лично мне кажется, что последний вариант наиболее чистый, но может быть я что-то упускаю? Какой из них лучше использовать, или это личные предпочтения?
Все разные.
typeof
принимает имя типа (который вы укажите во время компиляции).Метод gettype
становится типом времени выполнения экземпляра.это
возвращает true, если экземпляр в дереве наследования.<Н3 и GT;пример</Н3>
class Animal { }
class Dog : Animal { }
void PrintTypes(Animal a) {
Console.WriteLine(a.GetType() == typeof(Animal)); // false
Console.WriteLine(a is Animal); // true
Console.WriteLine(a.GetType() == typeof(Dog)); // true
Console.WriteLine(a is Dog); // true
}
Dog spot = new Dog();
PrintTypes(spot);
<ч>
как насчет вызова typeof(Т)`? Это тоже разрешена во время компиляции?
Да. Т всегда то, что тип выражения. Помните, что универсального метода в основном целая куча методов с соответствующим типом. Пример:
string Foo<T>(T parameter) { return typeof(T).Name; }
Animal probably_a_dog = new Dog();
Dog definitely_a_dog = new Dog();
Foo(probably_a_dog); // this calls Foo<Animal> and returns "Animal"
Foo<Animal>(probably_a_dog); // this is exactly the same as above
Foo<Dog>(probably_a_dog); // !!! This will not compile. The parameter expects a Dog, you cannot pass in an Animal.
Foo(definitely_a_dog); // this calls Foo<Dog> and returns "Dog"
Foo<Dog>(definitely_a_dog); // this is exactly the same as above.
Foo<Animal>(definitely_a_dog); // this calls Foo<Animal> and returns "Animal".
Foo((Animal)definitely_a_dog); // this does the same as above, returns "Animal"
Используйте typeof
, когда вы хотите получить тип во время компиляции. Используйте GetType
, если вы хотите получить тип во время исполнения. Использование is
редко бывает оправданным, так как оно выполняет приведение, и в большинстве случаев вы все равно приводите переменную.
Существует четвертый вариант, который вы не рассмотрели (особенно если вы собираетесь привести объект к найденному типу); это использование as
.
Foo foo = obj as Foo;
if (foo != null)
// your code here
При таком подходе используется только один каст:
if (obj is Foo)
Foo foo = (Foo)obj;
требует два.
1.
Type t = typeof(obj1);
if (t == typeof(int))
Это незаконно, потому что для вызова typeof работает только на видах, а не о переменных. Я предполагаю, что obj1 является переменной. В этом случае для вызова typeof является статическим, и делает свою работу во время компиляции, а не во время выполнения.
2.
if (obj1.GetType() == typeof(int))
Это верно, если obj1-это точно типа int. Если obj1 происходит от int, то, если условие будет ложным.
3.
if (obj1 is int)
Это верно, если obj1 является int, или если это происходит из класса int, или если он реализует интерфейс инт.
Type t = typeof(obj1);
if (t == typeof(int))
// Some code here
Это ошибка. Оператор typeof в C# может принимать только имена типов, а не объекты.
if (obj1.GetType() == typeof(int))
// Some code here
Это будет работать, но возможно не так, как вы ожидаете. Для типов значений, как вы'вэ показано здесь, это'цены приемлемые, но для ссылочных типов, он будет возвращать только true, если тип был таже тип, а не что-то другое в иерархии наследования. Например:
class Animal{}
class Dog : Animal{}
static void Foo(){
object o = new Dog();
if(o.GetType() == typeof(Animal))
Console.WriteLine("o is an animal");
Console.WriteLine("o is something else");
}
Это будет печатать в "O что-то еще"
В, потому что тип О
- это собака
, а не животное
. Однако вы можете сделать эту работу, если вы используете IsAssignableFrom
метод типа
класс.
if(typeof(Animal).IsAssignableFrom(o.GetType())) // note use of tested type
Console.WriteLine("o is an animal");
Эта методика все еще остается серьезной проблемой, хотя. Если переменная имеет значение NULL, то вызов `метод gettype () будет бросать исключение NullReferenceException. Поэтому, чтобы сделать его работать правильно, вы'd сделать:
if(o != null && typeof(Animal).IsAssignableFrom(o.GetType()))
Console.WriteLine("o is an animal");
При этом эквивалентное поведение это
ключевое слово. Следовательно, если это поведение вы хотите, вы должны использовать это
ключевое слово, которое является более читаемым и эффективным.
if(o is Animal)
Console.WriteLine("o is an animal");
В большинстве случаев, однако, это
ключевое слово до сих пор'т, что вы действительно хотите, потому что это'ы, как правило, не достаточно знать, что объект определенного типа. Как правило, вы хотите на самом деле использовать этот объект как экземпляр этого типа, который требует слишком отливку. И так вы можете найти себе написание кода такой:
if(o is Animal)
((Animal)o).Speak();
Но что делает среда CLR проверяет объект's печатает до двух раз. Он будет проверять его один раз, чтобы удовлетворить "есть" оператора, и если о
действительно животное
, мы делаем это снова проверить для проверки бросить.
Это's более эффективным, чтобы вместо этого:
Animal a = o as Animal;
if(a != null)
a.Speak();
Оператором " as " - это оттенок, который выиграл'т бросить исключение, если это не удается, вместо этого возвращая значение null. Таким образом, среда CLR проверяет объект's печатает только один раз, и после этого мы просто должны делать проверку на null, что является более эффективным.
Но будьте осторожны: многие люди попадают в ловушку с как
. Потому что это не'т выбросить исключения, некоторые люди думают, что это как-то "Безопасный" и бросили, а они используют его исключительно, избегая обычных слепков. Это приводит к ошибкам вроде этой:
(o as Animal).Speak();
В этом случае, разработчик явно предполагая, что " о "будет всегда быть "животное", и пока их предположение верно, то все работает нормально. Но если они'повторно не так, то, что они в конечном итоге с исключение NullReferenceException
. С завсегдатаев, они бы себя исключение invalidcastexception` вместо того, что бы более правильно определили проблему.
Иногда, эта ошибка может быть трудно найти:
class Foo{
readonly Animal animal;
public Foo(object o){
animal = o as Animal;
}
public void Interact(){
animal.Speak();
}
}
Это еще один случай, когда разработчик явно ожидая, o
, чтобы быть животное
каждый раз, но это'т очевидно, в конструкторе, где а
литой используется. Это's не очевидно, пока вы не дойдете до взаимодействовать
метод, где поле животное
, как ожидается, будет положительно назначены. В этом случае, не только вы в конечном итоге с сообщают исключение, но это вовсе'т кинули, пока потенциально гораздо позже, когда фактическая ошибка.
В резюме:
Если вам необходимо только знать, является ли или не является объект некоторого типа, использовать это
.
Если вам нужно обработать объект как экземпляр определенного типа, но вы Don'т знаем наверняка, что объект будет иметь тот тип, использовать как
и проверяем на нуль
.
Если вам нужно обработать объект как экземпляр определенного типа, и объект должен быть того типа, использовать обычный литой.
У меня был " тип " -собственность сравнить и не мог использовать это
(как my_type это _BaseTypetoLookFor
), но я мог бы использовать эти:
base_type.IsInstanceOfType(derived_object);
base_type.IsAssignableFrom(derived_type);
derived_type.IsSubClassOf(base_type);
Заметим, что IsInstanceOfTypeи
IsAssignableFromвозвращает true при сравнении тех же видах, где IsSubClassOf будет возвращать значение
false. И
IsSubclassOf` не работает на интерфейсах, где другие две. (См. Также этот вопрос и ответ.)
public class Animal {}
public interface ITrainable {}
public class Dog : Animal, ITrainable{}
Animal dog = new Dog();
typeof(Animal).IsInstanceOfType(dog); // true
typeof(Dog).IsInstanceOfType(dog); // true
typeof(ITrainable).IsInstanceOfType(dog); // true
typeof(Animal).IsAssignableFrom(dog.GetType()); // true
typeof(Dog).IsAssignableFrom(dog.GetType()); // true
typeof(ITrainable).IsAssignableFrom(dog.GetType()); // true
dog.GetType().IsSubclassOf(typeof(Animal)); // true
dog.GetType().IsSubclassOf(typeof(Dog)); // false
dog.GetType().IsSubclassOf(typeof(ITrainable)); // false
Если вы'вновь с использованием C# 7, то это время для обновления, чтобы Андрей Заяц's отличный ответ. Шаблон ввел хороший ярлык, который дает нам типизированной переменной в контексте если заявление, не требуя отдельной декларации/Cast и проверить:
if (obj1 is int integerValue)
{
integerValue++;
}
Это выглядит довольно впечатляющим для себя такой, но действительно сияет, когда у вас есть много возможных типов приходят в ваш режим. Ниже-старый способ предотвратить повторный кастинг:
Button button = obj1 as Button;
if (button != null)
{
// do stuff...
return;
}
TextBox text = obj1 as TextBox;
if (text != null)
{
// do stuff...
return;
}
Label label = obj1 as Label;
if (label != null)
{
// do stuff...
return;
}
// ... and so on
Работая вокруг сокращения этот код как можно больше, а также избежать дублирования слепков тот же объект всегда беспокоило меня. Выше хорошо сжимается при совпадении с шаблоном в следующем:
switch (obj1)
{
case Button button:
// do stuff...
break;
case TextBox text:
// do stuff...
break;
case Label label:
// do stuff...
break;
// and so on...
}
Редактировать: обновлен более новый способ, чтобы использовать переключатель, как на перст'ы комментарий.
Я предпочитаю <б>в</б>
Тем не менее, если вы're через <б>в</б>, вы'повторно, вероятно, в <их>нет</ЭМ> с помощью наследования надлежащим образом.
Предположим, что человек : сущность, и это животное : сущность. Корма виртуальный метод в Entity (сделать нейл счастлив)
в
class Person
{
// A Person should be able to Feed
// another Entity, but they way he feeds
// each is different
public override void Feed( Entity e )
{
if( e is Person )
{
// feed me
}
else if( e is Animal )
{
// ruff
}
}
}
А
в
class Person
{
public override void Feed( Person p )
{
// feed the person
}
public override void Feed( Animal a )
{
// feed the animal
}
}
Я считаю, что последний вариант также рассматривает наследование (например, Dog is Animal == true), что лучше в большинстве случаев.
Это зависит от того, что я делаю. Если мне нужно значение bool (скажем, чтобы определить, буду ли я приводить его к int), я использую is
. Если мне действительно нужен тип по какой-то причине (скажем, для передачи другому методу), я использую GetType()
.
System.Type type = typeof(int);
Example:
public class ExampleClass
{
public int sampleMember;
public void SampleMethod() {}
static void Main()
{
Type t = typeof(ExampleClass);
// Alternatively, you could use
// ExampleClass obj = new ExampleClass();
// Type t = obj.GetType();
Console.WriteLine("Methods:");
System.Reflection.MethodInfo[] methodInfo = t.GetMethods();
foreach (System.Reflection.MethodInfo mInfo in methodInfo)
Console.WriteLine(mInfo.ToString());
Console.WriteLine("Members:");
System.Reflection.MemberInfo[] memberInfo = t.GetMembers();
foreach (System.Reflection.MemberInfo mInfo in memberInfo)
Console.WriteLine(mInfo.ToString());
}
}
/*
Output:
Methods:
Void SampleMethod()
System.String ToString()
Boolean Equals(System.Object)
Int32 GetHashCode()
System.Type GetType()
Members:
Void SampleMethod()
System.String ToString()
Boolean Equals(System.Object)
Int32 GetHashCode()
System.Type GetType()
Void .ctor()
Int32 sampleMember
*/
class GetTypeTest
{
static void Main()
{
int radius = 3;
Console.WriteLine("Area = {0}", radius * radius * Math.PI);
Console.WriteLine("The type is {0}",
(radius * radius * Math.PI).GetType()
);
}
}
/*
Output:
Area = 28.2743338823081
The type is System.Double
*/
if (c is UserControl) c.Enabled = enable;
Вы можете использовать и"для вызова typeof()" и оператор в C#, но вы должны называть пространство имен, используя систему.ИО, вы должны использовать "и есть" сайта, если вы хотите проверить тип.
Тест производительности для вызова typeof() против метода gettype():
using System;
namespace ConsoleApplication1
{
class Program
{
enum TestEnum { E1, E2, E3 }
static void Main(string[] args)
{
{
var start = DateTime.UtcNow;
for (var i = 0; i < 1000000000; i++)
Test1(TestEnum.E2);
Console.WriteLine(DateTime.UtcNow - start);
}
{
var start = DateTime.UtcNow;
for (var i = 0; i < 1000000000; i++)
Test2(TestEnum.E2);
Console.WriteLine(DateTime.UtcNow - start);
}
Console.ReadLine();
}
static Type Test1<T>(T value) => typeof(T);
static Type Test2(object value) => value.GetType();
}
}
Результаты в режиме отладки:
00:00:08.4096636
00:00:10.8570657
Результаты в режиме релиза:
00:00:02.3799048
00:00:07.1797128