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 o
là Dog
, 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 IsAssignableFrom
phương thức của Type
lớ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ẽ ném 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 is
từ khóa. Do đó, nếu đây là hành vi bạn muốn, bạn nên sử dụng is
từ 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, is
từ khóa vẫn không phải là thứ bạn thực sự muốn, bởi vì thường thì 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 is
vận hành, và nếu o
thự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 o
sẽ 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 dàn diễn viên thông thường, họ sẽ có được một InvalidCastException
thay 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 o
là một Animal
mọ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 as
diễn viên được sử dụng. Không rõ ràng cho đến khi bạn có được Interact
phương pháp, nơi mà animal
trườ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 as
và 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.
as
!