etc./StackOverFlow

유형 검사: typeof, GetType 또는 is?

청렴결백한 만능 재주꾼 2022. 1. 25. 11:40
반응형

질문자 :jasonh


많은 사람들이 다음 코드를 사용하는 것을 보았습니다.

 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 은 인스턴스의 런타임 유형을 가져옵니다.
  • 인스턴스가 상속 트리에 있으면 is

예시

 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(T) 어떻습니까? 컴파일 타임에도 해결됩니까?

예. T는 항상 표현식의 유형입니다. 제네릭 메서드는 기본적으로 적절한 유형을 가진 메서드의 전체 묶음이라는 것을 기억하십시오. 예시:

 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"

Jimmy

컴파일 시간에 유형을 얻으려면 typeof 사용하십시오. 실행 시 유형을 얻으려면 GetType 사용하십시오. 어떤 경우 사용에 거의 없다는 is 그것이 캐스트를 수행하고, 대부분의 경우에, 당신은 어쨌든 변수를 캐스팅 끝으로.

고려하지 않은 네 번째 옵션이 있습니다(특히 찾은 유형으로 개체를 캐스트하려는 경우). 로 사용 as 입니다.

 Foo foo = obj as Foo; if (foo != null) // your code here

이것은 하나의 캐스트만 사용 하는 반면 이 접근 방식은 다음과 같습니다.

 if (obj is Foo) Foo foo = (Foo)obj;

2개가 필요합니다.


Community Wiki

1.

 Type t = typeof(obj1); if (t == typeof(int))

typeof 는 변수가 아닌 유형에서만 작동하기 때문에 이것은 불법입니다. obj1이 변수라고 가정합니다. 따라서 이러한 방식으로 typeof 는 정적이며 런타임 대신 컴파일 시간에 작업을 수행합니다.

2.

 if (obj1.GetType() == typeof(int))

obj1 이 정확히 int 유형인 경우에 true 합니다. obj1 int 에서 파생된 경우 if 조건은 false 입니다.

삼.

 if (obj1 is int)

이다 true 경우 obj1 이다 int , 또는 그것이라는 클래스에서 파생 된 경우 int , 또는 호출 인터페이스를 구현하는 경우 int .


Scott Langham

Type t = typeof(obj1); if (t == typeof(int)) // Some code here

이것은 오류입니다. C#의 typeof 연산자는 개체가 아닌 형식 이름만 사용할 수 있습니다.

 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 is something else" 의 종류 때문에, o 이다 Dog , 아니 Animal . Type 클래스 IsAssignableFrom 메서드를 사용하면 이 작업을 수행할 수 있습니다.

 if(typeof(Animal).IsAssignableFrom(o.GetType())) // note use of tested type Console.WriteLine("o is an animal");

그러나 이 기술은 여전히 큰 문제를 남깁니다. 변수가 null이면 GetType() 호출하면 NullReferenceException이 발생합니다. 따라서 올바르게 작동하려면 다음을 수행합니다.

 if(o != null && typeof(Animal).IsAssignableFrom(o.GetType())) Console.WriteLine("o is an animal");

is 키워드와 동일한 동작을 할 수 있습니다. 따라서 이것이 원하는 동작이라면 더 읽기 쉽고 효율적인 is

 if(o is Animal) Console.WriteLine("o is an animal");

그러나 대부분의 경우 is 키워드는 여전히 원하는 것이 아닙니다. 일반적으로 객체가 특정 유형이라는 것을 아는 것만으로는 충분하지 않기 때문입니다. 일반적으로 실제로 해당 객체를 해당 유형의 인스턴스로 사용하려고 하므로 캐스팅도 필요합니다. 따라서 다음과 같은 코드를 작성하는 자신을 발견할 수 있습니다.

 if(o is Animal) ((Animal)o).Speak();

그러나 CLR은 개체의 유형을 최대 두 번 확인합니다. is 연산자를 충족하기 위해 한 번 확인하고 o 가 실제로 Animal 이면 캐스트를 확인하기 위해 다시 확인합니다.

대신 이렇게 하는 것이 더 효율적입니다.

 Animal a = o as Animal; if(a != null) a.Speak();

as 연산자는 실패할 경우 예외를 throw하지 않고 대신 null 을 반환하는 캐스트입니다. 이런 식으로 CLR은 개체의 유형을 한 번만 확인하고 그 후에는 null 확인만 하면 되므로 더 효율적입니다.

그러나 주의하십시오. 많은 사람들이 as 의 함정에 빠지게 됩니다. 예외를 던지지 않기 때문에 어떤 사람들은 그것을 "안전한" 캐스트로 생각하고 독점적으로 사용하고 일반 캐스트를 기피합니다. 이로 인해 다음과 같은 오류가 발생합니다.

 (o as Animal).Speak();

이 경우 개발자는 o항상 Animal 이라고 분명히 가정하고 가정이 정확하기만 하면 모든 것이 잘 작동합니다. 그러나 그들이 틀렸다면 여기서 끝나는 것은 NullReferenceException 입니다. 일반 캐스트를 사용하면 문제를 보다 정확하게 식별할 수 InvalidCastException

때때로 이 버그는 찾기 어려울 수 있습니다.

 class Foo{ readonly Animal animal; public Foo(object o){ animal = o as Animal; } public void Interact(){ animal.Speak(); } }

o Animal 이 될 것이라고 분명히 예상하는 또 다른 경우 as 캐스트가 사용되는 생성자에서는 분명하지 않습니다. animal 필드가 긍정적으로 할당될 것으로 예상 Interact 방법에 도달할 때까지는 명확하지 않습니다. 이 경우 오해의 소지가 있는 예외가 발생할 뿐만 아니라 실제 오류가 발생한 때보다 훨씬 나중에 발생할 때까지 예외가 발생하지 않습니다.

요약해서 말하자면:

  • 당신은 단지 객체가 어떤 유형인지 여부를 확인해야하는 경우, 사용하는 is .

  • 객체를 특정 유형의 인스턴스로 처리해야 하지만 해당 유형의 객체인지 확실하지 않은 경우 as null 확인하십시오.

  • 객체를 특정 유형의 인스턴스로 처리해야 하고 객체가 해당 유형이어야 하는 경우 일반 캐스트를 사용하십시오.


P Daddy

C# 7을 사용하고 있다면 Andrew Hare의 훌륭한 답변을 업데이트할 때입니다. 패턴 일치 는 별도의 선언/캐스트 및 확인 없이 if 문의 컨텍스트 내에서 유형이 지정된 변수를 제공하는 멋진 단축키를 도입했습니다.

 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... }

편집: Palec의 의견에 따라 스위치를 사용하도록 더 긴 새 방법을 업데이트했습니다.


JoelC

나는 한 Type 에 비교 -property 및 수 사용하지 않을 is (같은 my_type is _BaseTypetoLookFor )하지만, 나는이를 사용할 수 있습니다 :

 base_type.IsInstanceOfType(derived_object); base_type.IsAssignableFrom(derived_type); derived_type.IsSubClassOf(base_type);

IsInstanceOfTypeIsAssignableFrom 은 동일한 유형을 비교할 때 true 반환 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

Yahoo Serious

나는 IS를 선호

즉, is 를 사용하는 경우 상속을 제대로 사용 하지 않을 가능성이 높습니다.

Person : Entity, 그리고 Animal : Entity라고 가정합니다. Feed는 Entity의 가상 메서드입니다(Neil을 행복하게 만들기 위해)

 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 } }

bobobobo

나는 마지막 것이 상속(예: Dog is Animal == true)도 살펴보고 대부분의 경우에 더 낫다고 생각합니다.


StriplingWarrior

내가 무엇을 하고 있는지에 달려 있습니다. bool 값이 필요한 경우(예: int로 캐스팅할지 결정하기 위해) is 사용합니다. 어떤 이유로 유형이 실제로 필요한 경우(예: 다른 메소드에 전달하기 위해) GetType() 합니다.


AllenG

마지막 것은 더 명확하고 명확하며 하위 유형도 확인합니다. 다른 것들은 다형성을 확인하지 않습니다.


thecoop

형식에 대한 System.Type 개체를 가져오는 데 사용됩니다. typeof 표현식은 다음 형식을 취합니다.

 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 */

이 샘플에서는 GetType 메서드를 사용하여 숫자 계산 결과를 포함하는 데 사용되는 형식을 확인합니다. 이는 결과 번호의 저장 요구 사항에 따라 다릅니다.

 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 */

Muhammad Awais

if (c is UserControl) c.Enabled = enable;

Paulos02

C#에서 "typeof()" 연산자를 사용할 수 있지만 System.IO를 사용하여 네임스페이스를 호출해야 합니다. 유형을 확인하려면 "is" 키워드를 사용해야 합니다.


androidrill

성능 테스트 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

Alexander Vasilyev

출처 : http:www.stackoverflow.com/questions/983030/type-checking-typeof-gettype-or-is

반응형