1.3k

Tôi đã thấy nhiều người sử dụng mã sau đây:

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

Nhưng tôi biết bạn cũng có thể làm điều này:

if (obj1.GetType() == typeof(int))
    // Some code here

Hoặc này:

if (obj1 is int)
    // Some code here

Cá nhân, tôi cảm thấy cái cuối cùng là sạch nhất, nhưng tôi có thiếu thứ gì không? Cái nào là tốt nhất để sử dụng, hoặc đó là sở thích cá nhân?

|
  • 23
  • 77

    askhông thực sự kiểm tra kiểu mặc dù ...

    – Hồ Minh Tuấn 00:48:03 08/10/2009
  • 45

    aschắc chắn là một hình thức kiểm tra kiểu, mỗi bit nhiều như isvậy! Nó sử dụng hiệu quả isđằng sau hậu trường và được sử dụng ở mọi nơi trong MSDN ở những nơi giúp cải thiện độ sạch của mã so với is. Thay vì kiểm tra istrước, một lệnh gọi để asthiết lập một biến được gõ sẵn sàng để sử dụng: Nếu nó không có giá trị, hãy trả lời một cách thích hợp; nếu không, tiến hành. Chắc chắn một cái gì đó tôi đã thấy và sử dụng khá nhiều.

    – Ngô Ngọc Thái 16:07:00 20/08/2014
  • 14

    Có sự khác biệt đáng kể về hiệu suất trong việc ủng hộ as/ is(được đề cập trong stackoverflow.com/a/27813381/477420 ) giả sử các tác phẩm ngữ nghĩa của nó cho trường hợp của bạn.

    – Hồ Hữu Lương 06:46:05 07/01/2015
  • @samusarin nó không "sử dụng" sự phản chiếu. Các GetTypephương pháp bạn đang liên kết đến là trong System.Reflection.Assembly- một phương pháp hoàn toàn khác nhau và không liên quan ở đây.

    – Dương Cường Quốc 20:59:17 11/08/2017
1.6k

Tất cả đều khác nhau.

  • typeof lấy một tên loại (mà bạn chỉ định tại thời gian biên dịch).
  • GetType được loại thời gian chạy của một thể hiện.
  • is trả về true nếu một thể hiện trong cây thừa kế.

Thí dụ

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);

Thế còn typeof(T)? Nó cũng được giải quyết tại thời gian biên dịch?

Vâng. T luôn là kiểu biểu thức. Hãy nhớ rằng, một phương thức chung về cơ bản là một loạt các phương thức với loại thích hợp. Thí dụ:

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"
|
  • 1

    À, vậy nếu tôi có một lớp Ford xuất phát từ Xe hơi và một thể hiện của Ford, thì việc kiểm tra "là Xe hơi" trong trường hợp đó sẽ là sự thật. Có ý nghĩa!

    – Huỳnh Xuân Khoa 19:19:33 11/06/2009
  • 1

    Để làm rõ, tôi đã nhận thức được điều đó, nhưng tôi đã nhận xét trước khi bạn thêm một mẫu mã. Tôi muốn cố gắng thêm một số tiếng Anh rõ ràng vào câu trả lời đã xuất sắc của bạn.

    – Dương Minh Xuân 19:25:13 11/06/2009
  • 1

    @Jimmy Vậy còn hiệu suất thì sao? typeofso với GetType()?

    – Ngô Ðình Nam 04:59:40 26/01/2012
  • 1

    @Shimmy nếu typeof được đánh giá tại thời gian biên dịch và GetType () được đánh giá khi chạy, thì có nghĩa là GetType () phải chịu một cú đánh hiệu suất nhẹ

    – Hồ Ðức Tâm 13:35:06 10/12/2012
  • 1

    @PrerakK new Dog().GetType() is Animaltrả về false (và cả phiên bản khác của bạn) vì .GetType()trả về một đối tượng thuộc loại TypeTypekhông phải là một Animal.

    – Tạ Minh Nghĩa 09:45:46 07/11/2014
177

Sử dụng typeofkhi bạn muốn lấy loại tại thời gian biên dịch . Sử dụng GetTypekhi bạn muốn lấy loại tại thời điểm thực hiện . Hiếm khi có bất kỳ trường hợp nào được sử dụng isvì nó thực hiện và trong hầu hết các trường hợp, cuối cùng bạn vẫn truyền biến.

Có một tùy chọn thứ tư mà bạn chưa xem xét (đặc biệt là nếu bạn định chuyển một đối tượng sang loại bạn tìm thấy); đó là sử dụng as.

Foo foo = obj as Foo;

if (foo != null)
    // your code here

Điều này chỉ sử dụng một diễn viên trong khi phương pháp này:

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

đòi hỏi hai .

|
  • 1

    Với những thay đổi trong .NET 4 isvẫn thực hiện một cast?

    – Huỳnh Xuân Khoa 21:04:51 21/03/2013
  • 1

    Câu trả lời này có đúng không? Có đúng là bạn thực sự có thể chuyển một thể hiện vào typeof () không? Kinh nghiệm của tôi là Không. Nhưng tôi đoán nói chung việc kiểm tra một cá thể có thể phải xảy ra trong thời gian chạy, trong khi kiểm tra một lớp nên có thể thực hiện được trong thời gian biên dịch.

    – Dương Minh Xuân 02:13:53 08/10/2013
  • 1

    @jon (4 năm sau q.), Không, bạn không thể chuyển một ví dụ vào typeof()và câu trả lời này không gợi ý bạn có thể. Bạn vượt qua trong loại thay vào đó, tức là, typeof(string)hoạt động, typeof("foo")không.

    – Ngô Ðình Nam 01:30:59 20/09/2017
  • 1

    Tôi không tin isdiễn xuất như vậy, hoạt động khá đặc biệt ở IL.

    – Hồ Ðức Tâm 20:20:08 22/10/2018
66

1.

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

Điều này là bất hợp pháp, bởi vì typeof chỉ hoạt động trên các loại, không phải trên các biến. Tôi giả sử obj1 là một biến. Vì vậy, theo cách này, typeof là tĩnh và thực hiện công việc của nó tại thời gian biên dịch thay vì thời gian chạy.

2.

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

Điều này đúng nếu obj1 chính xác là kiểu int. Nếu obj1 xuất phát từ int, điều kiện if sẽ là false.

3.

if (obj1 is int)

Điều này đúng nếu obj1 là int hoặc nếu nó xuất phát từ một lớp được gọi là int hoặc nếu nó thực hiện một giao diện gọi là int.

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

Đây là một lỗi. Toán tử typeof trong C # chỉ có thể lấy tên kiểu, không phải đối tượng.

if (obj1.GetType() == typeof(int))
    // Some code here

Điều này sẽ làm việc, nhưng có thể không như bạn mong đợi. Đối với các loại giá trị, như bạn đã trình bày ở đây, có thể chấp nhận được, nhưng đối với các loại tham chiếu, nó sẽ chỉ trả về đúng nếu loại đó là cùng loại, không phải là thứ khác trong hệ thống phân cấp thừa kế. Ví dụ:

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");
}

Điều này sẽ in "o is something else", bởi vì loại oDog, không Animal. Bạn có thể làm cho công việc này, tuy nhiên, nếu bạn sử dụng IsAssignableFromphương thức của Typelớp.

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

Kỹ thuật này vẫn để lại một vấn đề lớn, mặc dù. Nếu biến của bạn là null, lệnh gọi GetType()sẽ đưa ra NullReferenceException. Vì vậy, để làm cho nó hoạt động chính xác, bạn sẽ làm:

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

Với điều này, bạn có hành vi tương đương của istừ khóa. Do đó, nếu đây là hành vi bạn muốn, bạn nên sử dụng istừ khóa, dễ đọc hơn và hiệu quả hơn.

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

Tuy nhiên, trong hầu hết các trường hợp, istừ khóa vẫn không phải là thứ bạn thực sự muốn, bởi vì thường không đủ để biết rằng một đối tượng thuộc một loại nhất định. Thông thường, bạn muốn thực sự sử dụng đối tượng đó như là một thể hiện của loại đó, cũng yêu cầu truyền nó. Và vì vậy bạn có thể thấy mình viết mã như thế này:

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

Nhưng điều đó làm cho CLR kiểm tra loại đối tượng lên đến hai lần. Nó sẽ kiểm tra nó một lần để thỏa mãn người isvận hành, và nếu othực sự là một Animal, chúng tôi làm cho nó kiểm tra lại để xác thực diễn viên.

Thay vào đó, hiệu quả hơn là làm điều này:

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

Nhà asđiều hành là một diễn viên sẽ không ném ngoại lệ nếu thất bại, thay vào đó trở lại null. Bằng cách này, CLR kiểm tra loại đối tượng chỉ một lần và sau đó, chúng ta chỉ cần thực hiện kiểm tra null, hiệu quả hơn.

Nhưng hãy cẩn thận: nhiều người rơi vào một cái bẫy với as. Bởi vì nó không đưa ra ngoại lệ, một số người nghĩ rằng đó là dàn diễn viên "an toàn" và họ sử dụng nó một cách độc quyền, làm cho các diễn viên thông thường lẩn tránh. Điều này dẫn đến các lỗi như thế này:

(o as Animal).Speak();

Trong trường hợp này, nhà phát triển rõ ràng giả định rằng osẽ luôn luôn là một Animal, và miễn là giả định của họ là chính xác, mọi thứ đều hoạt động tốt. Nhưng nếu họ sai, thì cái họ kết thúc ở đây là a NullReferenceException. Với một diễn viên thông thường, họ sẽ có được một InvalidCastExceptionthay thế, điều này sẽ xác định chính xác hơn vấn đề.

Đôi khi, lỗi này có thể khó tìm:

class Foo{
    readonly Animal animal;

    public Foo(object o){
        animal = o as Animal;
    }

    public void Interact(){
        animal.Speak();
    }
}

Đây là một trường hợp các nhà phát triển được rõ ràng mong đợi olà một Animalmọi thời gian, nhưng điều này là không rõ ràng trong các nhà xây dựng, nơi mà các asdiễn viên được sử dụng. Không rõ ràng cho đến khi bạn có được Interactphương thức, nơi mà animaltrường được dự kiến ​​sẽ được gán tích cực. Trong trường hợp này, không chỉ bạn kết thúc với một ngoại lệ sai lệch, mà nó còn không được ném cho đến khi có khả năng muộn hơn nhiều so với khi xảy ra lỗi thực tế.

Tóm tắt:

  • Nếu bạn chỉ cần biết liệu một đối tượng có thuộc loại nào đó hay không, hãy sử dụng is.

  • Nếu bạn cần coi một đối tượng là một thể hiện của một loại nhất định, nhưng bạn không biết chắc chắn rằng đối tượng đó sẽ thuộc loại đó, hãy sử dụng asvà kiểm tra null.

  • Nếu bạn cần coi một đối tượng là một thể hiện của một loại nhất định và đối tượng được cho là thuộc loại đó, hãy sử dụng một biểu mẫu thông thường.

|
  • 1

    Có gì sai với điều này nếu (o là Animal) ((Animal) o) .Speak (); ? bạn có thể vui lòng cho biết thêm chi tiết?

    – Bùi Hồng Thủy 22:11:31 10/01/2017
  • 1

    @batmaci: đó là câu trả lời - nó gây ra hai loại kiểm tra. Lần đầu tiên o is Animal, yêu cầu CLR kiểm tra xem loại biến ocó phải là một không Animal. Lần thứ hai nó kiểm tra là khi nó thực hiện trong câu lệnh ((Animal)o).Speak(). Thay vì kiểm tra hai lần, hãy kiểm tra một lần bằng cách sử dụng as.

    – Võ Kim Phú 15:15:57 28/07/2018
13

Tôi đã có một Type-perperty để so sánh và không thể sử dụng is(như my_type is _BaseTypetoLookFor), nhưng tôi có thể sử dụng những thứ này:

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

Lưu ý rằng IsInstanceOfTypeIsAssignableFromtrả về truekhi so sánh các loại tương tự, nơi IsSubClassOf sẽ trả về false. IsSubclassOfkhông hoạt động trên các giao diện, nơi hai cái kia làm. (Xem thêm câu hỏi và câu trả lời này .)

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

Nếu bạn đang sử dụng C # 7, thì đã đến lúc cập nhật câu trả lời tuyệt vời của Andrew Hare. Kết hợp mẫu đã giới thiệu một phím tắt đẹp cung cấp cho chúng ta một biến được nhập trong ngữ cảnh của câu lệnh if, mà không yêu cầu khai báo / truyền riêng và kiểm tra:

if (obj1 is int integerValue)
{
    integerValue++;
}

Điều này có vẻ khá áp đảo đối với một diễn viên như thế này, nhưng thực sự tỏa sáng khi bạn có nhiều loại có thể đi vào thói quen của bạn. Dưới đây là cách cũ để tránh truyền hai lần:

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

Làm việc xung quanh thu nhỏ mã này càng nhiều càng tốt, cũng như tránh các phôi trùng lặp của cùng một đối tượng luôn làm phiền tôi. Ở trên được nén độc đáo với mô hình phù hợp với sau:

switch (obj1)
{
    case Button button:
        // do stuff...
        break;
    case TextBox text:
        // do stuff...
        break;
    case Label label:
        // do stuff...
        break;
    // and so on...
}

EDIT: Đã cập nhật phương thức mới dài hơn để sử dụng một công tắc theo nhận xét của Palec.

|
8

Tôi thích

Điều đó nói rằng, nếu bạn đang sử dụng , bạn đang có khả năng không sử dụng thừa kế đúng cách.

Giả sử Người đó: Thực thể và Động vật đó: Thực thể. Nguồn cấp dữ liệu là một phương thức ảo trong Thực thể (để làm Neil hài lòng)

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

Hơn

class Person
{
  public override void Feed( Person p )
  {
    // feed the person
  }
  public override void Feed( Animal a )
  {
    // feed the animal
  }
}
|
  • 1

    Đúng, tôi sẽ không bao giờ làm điều trước, khi biết rằng Người bắt nguồn từ Động vật.

    – Bùi Hồng Thủy 19:22:01 11/06/2009
  • 1

    Cái sau cũng không thực sự sử dụng thừa kế. Foo nên là một phương thức ảo của Thực thể được ghi đè trong Người và Động vật.

    – Võ Kim Phú 19:31:30 11/06/2009
  • 1

    @bobobobo Tôi nghĩ bạn có nghĩa là "quá tải", không phải "thừa kế".

    – Tạ Tuệ Lâm 19:42:10 11/06/2009
  • 1

    @lc: Không, ý tôi là thừa kế. Ví dụ đầu tiên là một cách không chính xác (sử dụng ) để có được hành vi khác nhau. Ví dụ thứ hai sử dụng quá tải có, nhưng tránh sử dụng .

    – Nguyễn Ngọc Thư 19:47:45 11/06/2009
  • 1

    Vấn đề với ví dụ là nó sẽ không mở rộng. Nếu bạn đã thêm các thực thể mới cần ăn (ví dụ: Côn trùng hoặc Quái vật), bạn sẽ cần thêm một phương thức mới trong lớp Thực thể và sau đó ghi đè lên nó trong các lớp con sẽ nuôi nó. Điều này không thích hợp hơn danh sách nếu (thực thể là X) khác nếu (thực thể là Y) ... Điều này vi phạm LSP và OCP, kế thừa có lẽ không phải là giải pháp tốt nhất cho vấn đề. Một số hình thức của phái đoàn có thể sẽ được ưa thích.

    – Dương Diễm Sương 21:12:22 11/06/2009
5

Bạn có thể sử dụng toán tử "typeof ()" trong C # nhưng bạn cần gọi không gian tên bằng System.IO; Bạn phải sử dụng từ khóa "là" nếu bạn muốn kiểm tra loại.

|
  • 1

    typeofkhông được định nghĩa trong một không gian tên, nó là một từ khóa. System.IOkhông có gì để làm với điều này.

    – Bùi Quang Minh 00:13:36 18/09/2015
5

Tôi tin rằng người cuối cùng cũng nhìn vào sự kế thừa (ví dụ Dog là Animal == true), điều này tốt hơn trong hầu hết các trường hợp.

|
3
if (c is UserControl) c.Enabled = enable;
|
  • 1

    Vui lòng chỉnh sửa với nhiều thông tin hơn. Các câu trả lời chỉ dành cho mã và "thử cái này" không được khuyến khích, vì chúng không chứa nội dung có thể tìm kiếm và không giải thích lý do tại sao ai đó nên "thử cái này".

    – Bùi Quang Minh 14:33:12 06/09/2016
2

Nó phụ thuộc vào những gì tôi đang làm. Nếu tôi cần một giá trị bool (giả sử, để xác định xem tôi có chuyển sang int không), tôi sẽ sử dụng is. Nếu tôi thực sự cần loại vì một số lý do (giả sử, để chuyển sang một số phương pháp khác) tôi sẽ sử dụng GetType().

|
  • 1

    Điểm tốt. Tôi quên đề cập rằng tôi đã nhận được câu hỏi này sau khi xem một số câu trả lời sử dụng câu lệnh if để kiểm tra một loại.

    – Bùi Quang Minh 19:20:47 11/06/2009
0

Được sử dụng để lấy đối tượng System.Type cho một loại. Một biểu thức typeof có dạng sau:

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

Mẫu này sử dụng phương thức GetType để xác định loại được sử dụng để chứa kết quả của phép tính số. Điều này phụ thuộc vào yêu cầu lưu trữ của số kết quả.

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

Cái cuối cùng sạch hơn, rõ ràng hơn và cũng kiểm tra các kiểu con. Những người khác không kiểm tra tính đa hình.

|

Câu trả lời của bạn (> 20 ký tự)

Bằng cách click "Đăng trả lời", bạn đồng ý với Điều khoản dịch vụ, Chính sách bảo mật and Chính sách cookie của chúng tôi.

Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ hoặc hỏi câu hỏi của bạn.