I've seen many people use the following code:
Type t = typeof(SomeType);
if (t == typeof(int))
// Some code here
But I know you could also do this:
if (obj1.GetType() == typeof(int))
// Some code here
Or this:
if (obj1 is int)
// Some code here
Personally, I feel the last one is the cleanest, but is there something I'm missing? Which one is the best to use, or is it personal preference?
as
! - anyone as
isn't really type checking though... - anyone as
is certainly a form of type-checking, every bit as much as is
is! It effectively uses is
behind the scenes, and is used all over the place in MSDN in places where it improves code cleanliness versus is
. Instead of checking for is
first, a call to as
establishes a typed variable that's ready for use: If it's null, respond appropriately; otherwise, proceed. Certainly something I've seen and used quite a bit. - anyone as
/is
(covered in stackoverflow.com/a/27813381/477420) assuming its semantic works for your case. - anyone GetType
method you are linking to is in System.Reflection.Assembly
-- a completely different method and irrelevant here. - anyone All are different.
typeof
takes a type name (which you specify at compile time).GetType
gets the runtime type of an instance.is
returns true if an instance is in the inheritance tree.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);
What about
typeof(T)
? Is it also resolved at compile time?
Yes. T is always what the type of the expression is. Remember, a generic method is basically a whole bunch of methods with the appropriate type. Example:
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"
Answered 2023-09-21 08:09:40
new Dog().GetType() is Animal
returns false (and your other version as well) since .GetType()
returns an object of type Type
, and Type
is not an Animal
. - anyone is
, if the result (either true
or false
) is known at compile-time, you get a compile-time warning. This means you should change your code! Example 1: void M(Dog d) { var test = d is System.Exception; }
It can be seen at compile-time that a null reference or an instance of Dog
can never be an instance of System.Exception
because the involved types are class
types and each class
can have only one direct base class. Example 2: void M(int i) { var test = i is IConvertible; }
It can be seen at compile-time that this is always true (i
is never null). - anyone Use typeof
when you want to get the type at compilation time. Use GetType
when you want to get the type at execution time. There are rarely any cases to use is
as it does a cast and, in most cases, you end up casting the variable anyway.
There is a fourth option that you haven't considered (especially if you are going to cast an object to the type you find as well); that is to use as
.
Foo foo = obj as Foo;
if (foo != null)
// your code here
This only uses one cast whereas this approach:
if (obj is Foo)
Foo foo = (Foo)obj;
requires two.
Update (Jan 2020):
Example:
if(obj is Foo newLocalFoo)
{
// For example, you can now reference 'newLocalFoo' in this local scope
Console.WriteLine(newLocalFoo);
}
Answered 2023-09-21 08:09:40
is
still perform a cast? - anyone typeof()
, and this answer doesn't suggest you can. You pass in the type instead, i.e., typeof(string)
works, typeof("foo")
does not. - anyone is
performs cast as such, rather special operation in IL. - anyone if (obj is Foo foo) { /* use foo here */ }
- anyone 1.
Type t = typeof(obj1);
if (t == typeof(int))
This is illegal, because typeof
only works on types, not on variables. I assume obj1 is a variable. So, in this way typeof
is static, and does its work at compile time instead of runtime.
2.
if (obj1.GetType() == typeof(int))
This is true
if obj1
is exactly of type int
. If obj1
derives from int
, the if condition will be false
.
3.
if (obj1 is int)
This is true
if obj1
is an int
, or if it derives from a class called int
, or if it implements an interface called int
.
Answered 2023-09-21 08:09:40
Type t = typeof(obj1);
if (t == typeof(int))
// Some code here
This is an error. The typeof operator in C# can only take type names, not objects.
if (obj1.GetType() == typeof(int))
// Some code here
This will work, but maybe not as you would expect. For value types, as you've shown here, it's acceptable, but for reference types, it would only return true if the type was the exact same type, not something else in the inheritance hierarchy. For instance:
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");
}
This would print "o is something else"
, because the type of o
is Dog
, not Animal
. You can make this work, however, if you use the IsAssignableFrom
method of the Type
class.
if(typeof(Animal).IsAssignableFrom(o.GetType())) // note use of tested type
Console.WriteLine("o is an animal");
This technique still leaves a major problem, though. If your variable is null, the call to GetType()
will throw a NullReferenceException. So to make it work correctly, you'd do:
if(o != null && typeof(Animal).IsAssignableFrom(o.GetType()))
Console.WriteLine("o is an animal");
With this, you have equivalent behavior of the is
keyword. Hence, if this is the behavior you want, you should use the is
keyword, which is more readable and more efficient.
if(o is Animal)
Console.WriteLine("o is an animal");
In most cases, though, the is
keyword still isn't what you really want, because it's usually not enough just to know that an object is of a certain type. Usually, you want to actually use that object as an instance of that type, which requires casting it too. And so you may find yourself writing code like this:
if(o is Animal)
((Animal)o).Speak();
But that makes the CLR check the object's type up to two times. It will check it once to satisfy the is
operator, and if o
is indeed an Animal
, we make it check again to validate the cast.
It's more efficient to do this instead:
Animal a = o as Animal;
if(a != null)
a.Speak();
The as
operator is a cast that won't throw an exception if it fails, instead returning null
. This way, the CLR checks the object's type just once, and after that, we just need to do a null check, which is more efficient.
But beware: many people fall into a trap with as
. Because it doesn't throw exceptions, some people think of it as a "safe" cast, and they use it exclusively, shunning regular casts. This leads to errors like this:
(o as Animal).Speak();
In this case, the developer is clearly assuming that o
will always be an Animal
, and as long as their assumption is correct, everything works fine. But if they're wrong, then what they end up with here is a NullReferenceException
. With a regular cast, they would have gotten an InvalidCastException
instead, which would have more correctly identified the problem.
Sometimes, this bug can be hard to find:
class Foo{
readonly Animal animal;
public Foo(object o){
animal = o as Animal;
}
public void Interact(){
animal.Speak();
}
}
This is another case where the developer is clearly expecting o
to be an Animal
every time, but this isn't obvious in the constructor, where the as
cast is used. It's not obvious until you get to the Interact
method, where the animal
field is expected to be positively assigned. In this case, not only do you end up with a misleading exception, but it isn't thrown until potentially much later than when the actual error occurred.
In summary:
If you only need to know whether or not an object is of some type, use is
.
If you need to treat an object as an instance of a certain type, but you don't know for sure that the object will be of that type, use as
and check for null
.
If you need to treat an object as an instance of a certain type, and the object is supposed to be of that type, use a regular cast.
Answered 2023-09-21 08:09:40
o is Animal
, which requires the CLR to check if the type of the variable o
is an Animal
. The second time it checks is when it casts in the statement ((Animal)o).Speak()
. Rather than check twice, check once using as
. - anyone If you're using C# 7, then it is time for an update to Andrew Hare's great answer. Pattern matching has introduced a nice shortcut that gives us a typed variable within the context of the if statement, without requiring a separate declaration/cast and check:
if (obj1 is int integerValue)
{
integerValue++;
}
This looks pretty underwhelming for a single cast like this, but really shines when you have many possible types coming into your routine. The below is the old way to avoid casting twice:
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
Working around shrinking this code as much as possible, as well as avoiding duplicate casts of the same object has always bothered me. The above is nicely compressed with pattern matching to the following:
switch (obj1)
{
case Button button:
// do stuff...
break;
case TextBox text:
// do stuff...
break;
case Label label:
// do stuff...
break;
// and so on...
}
EDIT: Updated the longer new method to use a switch as per Palec's comment.
Answered 2023-09-21 08:09:40
switch
statement with pattern matching is advisable in this case. - anyone if (obj1 is int integerValue) { integerValue++; }
- anyone _
). e.g. case Button _:
. Works great, much less noise than a big if statement. - anyone I had a Type
-property to compare to and could not use is
(like my_type is _BaseTypetoLookFor
), but I could use these:
base_type.IsInstanceOfType(derived_object);
base_type.IsAssignableFrom(derived_type);
derived_type.IsSubClassOf(base_type);
Notice that IsInstanceOfType
and IsAssignableFrom
return true
when comparing the same types, where IsSubClassOf will return false
. And IsSubclassOf
does not work on interfaces, where the other two do. (See also this question and answer.)
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
Answered 2023-09-21 08:09:40
I prefer is
That said, if you're using is, you're likely not using inheritance properly.
Assume that Person : Entity, and that Animal : Entity. Feed is a virtual method in Entity (to make Neil happy)
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
}
}
}
Rather
class Person
{
public override void Feed( Person p )
{
// feed the person
}
public override void Feed( Animal a )
{
// feed the animal
}
}
Answered 2023-09-21 08:09:40
I believe the last one also looks at inheritance (e.g. Dog is Animal == true), which is better in most cases.
Answered 2023-09-21 08:09:40
It depends on what I'm doing. If I need a bool value (say, to determine if I'll cast to an int), I'll use is
. If I actually need the type for some reason (say, to pass to some other method) I'll use GetType()
.
Answered 2023-09-21 08:09:40
The last one is cleaner, more obvious, and also checks for subtypes. The others do not check for polymorphism.
Answered 2023-09-21 08:09:40
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
*/
Answered 2023-09-21 08:09:40
I found checking if the type of something is equal to something is done by the following:
variableName.GetType() == typeof(int)
Answered 2023-09-21 08:09:40
if (c is UserControl) c.Enabled = enable;
Answered 2023-09-21 08:09:40
You can use "typeof()" operator in C# but you need to call the namespace using System.IO; You must use "is" keyword if you wish to check for a type.
Answered 2023-09-21 08:09:40
typeof
is not defined in a namespace, it is a keyword. System.IO
has nothing to do with this. - anyone Performance test typeof() vs 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();
}
}
Results in debug mode:
00:00:08.4096636
00:00:10.8570657
Results in release mode:
00:00:02.3799048
00:00:07.1797128
Answered 2023-09-21 08:09:40
DateTime
should not be used if you're concerned about times below 100ms, since it uses the OS's timeframe. Comparatively with Stopwatch
, which uses the processors' Tick
, the resolution used by a DateTime
in Win7 is a whooping 15ms. - anyone