C #: 'là' từ khóa và kiểm tra Không


287

Đây là một câu hỏi ngớ ngẩn, nhưng bạn có thể sử dụng mã này để kiểm tra xem một cái gì đó là một loại cụ thể ...

if (child is IContainer) { //....

Có cách nào thanh lịch hơn để kiểm tra ví dụ "KHÔNG" không?

if (!(child is IContainer)) { //A little ugly... silly, yes I know...

//these don't work :)
if (child !is IContainer) {
if (child isnt IContainer) { 
if (child aint IContainer) { 
if (child isnotafreaking IContainer) { 

Vâng, vâng ... câu hỏi ngớ ngẩn ....

Bởi vì có một số câu hỏi về mã trông như thế nào, nó chỉ là một sự trở lại đơn giản khi bắt đầu một phương thức.

public void Update(DocumentPart part) {
    part.Update();
    if (!(DocumentPart is IContainer)) { return; }
    foreach(DocumentPart child in ((IContainer)part).Children) {
       //...etc...

105
Cá nhân tôi thích "đứa trẻ không chú ý ...". Tôi đang bỏ phiếu để đưa từ khóa đó vào C # 5
Joseph

Tôi quan tâm để biết tình hình bạn sẽ sử dụng này? Phần "khác" của mã này trông như thế nào và bạn không thể đảo ngược bài kiểm tra? Nếu mã của bạn đang nói "nếu trẻ em không phải là IContainer thì hãy ném ngoại lệ" hoặc "nếu trẻ không phải là IContainer thì có thể đó là IFoo vì vậy tôi sẽ thử tiếp theo" thì có phải là một tuyên bố khác ngụ ý ở đó không? Có lẽ tôi đang thiếu một cái gì đó.
Martin Peck

1
@MartinPeck, có thể không có mệnh đề nào khác. Đó là lý do tôi tìm kiếm cái này.
Joshua Walsh

@MartinPeck đây là một mẫu: if (!(argument is MapsControlViewModel vm)) { return; }- Tôi có thể đảo ngược if và đặt phần còn lại của phương thức bên trong dấu ngoặc if, nhưng sau đó tôi sẽ nhận được mã cây Giáng sinh, với rất nhiều dấu ngoặc đóng ở cuối phương thức. Điều đó ít đọc hơn nhiều.
ANeves

có lẽ những gì chúng ta cần nói chung là những ifnottuyên bố
Dave Cousineau

Câu trả lời:


301
if(!(child is IContainer))

là toán tử duy nhất để đi (không có IsNottoán tử).

Bạn có thể xây dựng một phương thức mở rộng thực hiện nó:

public static bool IsA<T>(this object obj) {
    return obj is T;
}

và sau đó sử dụng nó để:

if (!child.IsA<IContainer>())

Và bạn có thể làm theo chủ đề của bạn:

public static bool IsNotAFreaking<T>(this object obj) {
    return !(obj is T);
}

if (child.IsNotAFreaking<IContainer>()) { // ...

Cập nhật (xem xét đoạn mã của OP):

Vì bạn thực sự đang truyền giá trị sau đó, bạn chỉ có thể sử dụng asthay thế:

public void Update(DocumentPart part) {
    part.Update();
    IContainer containerPart = part as IContainer;
    if(containerPart == null) return;
    foreach(DocumentPart child in containerPart.Children) { // omit the cast.
       //...etc...

1
Ck: Ý tôi là theo nghĩa của các nhà khai thác, không có IsNotgì cả.
Mehrdad Afshari

5
Đúng. Tôi đang đùa trong trường hợp không rõ ràng.
Mehrdad Afshari

111

Bạn có thể làm theo cách này:

object a = new StreamWriter("c:\\temp\\test.txt");

if (a is TextReader == false)
{
   Console.WriteLine("failed");
}

2
@Frank - vâng, từ khóa là một boolean, mà bạn có thể so sánh với false
cjk

32
@Frank nó hoạt động vì iscó quyền ưu tiên cao hơn so với ==. Lý do duy nhất bạn không thể sử dụng !x is flà nó có ít quyền ưu tiên hơn !.
Mehrdad Afshari

Tôi thích điều này nhưng nó dường như không hoạt động đúng khi giới thiệu một biến, mặc dù nó nên. if (a is TextReader reader == false)"nên" hoạt động, nhưng nó sẽ không cho phép bạn sử dụng biến trong đường dẫn thực sự nói rằng nó có thể chưa được khởi tạo.
Dave Cousineau

@DaveCousineau - Thông thường bạn sẽ đánh máy và giới thiệu một biến khi bạn muốn sử dụng biến được giới thiệu. Tôi không chắc chắn biến số này sẽ hữu ích như thế nào nếu lỗi đánh máy không thành công. (Từ chối trách nhiệm - Tôi thấy tính năng "Khớp mẫu" có tên kém và xấu như mùi mã khi sử dụng outtham số)
StingyJack

@StingyJack có một số trục trặc trong đó trong đường dẫn thực , biến được coi là chưa được khởi tạo. ngay cả khi bạn nói if (a is TextReader reader == true)nó nghĩ rằng biến là chưa được khởi tạo.
Dave Cousineau

11

Tại sao không chỉ sử dụng khác?

if (child is IContainer)
{
  //
}
else
{
  // Do what you want here
}

Nó gọn gàng quen thuộc và đơn giản?


3
Không có gì sai với nó - đây chỉ là một câu hỏi nitpick. Tôi muốn thoát ngay lập tức một chức năng nếu một cái gì đó không phải là một loại cụ thể. Tôi đã thực hiện nó (! (Đứa trẻ là một cái gì đó)) mãi mãi, nhưng tôi nghĩ tôi chắc chắn rằng không có cách nào tốt hơn.
Hugoware

1
Với mã mẫu trong câu hỏi, điều này có nghĩa là dấu ngoặc rỗng. Điều đó không giống như một sự thay thế hợp lý.
ANeves

9

Cách bạn có nó là tốt nhưng bạn có thể tạo một tập hợp các phương thức mở rộng để làm cho "một cách thanh lịch hơn để kiểm tra ví dụ 'KHÔNG'."

public static bool Is<T>(this object myObject)
{
    return (myObject is T);
}

public static bool IsNot<T>(this object myObject)
{
    return !(myObject is T);
}

Sau đó, bạn có thể viết:

if (child.IsNot<IContainer>())
{
    // child is not an IContainer
}

7

Điều này chưa được đề cập. Nó hoạt động và tôi nghĩ rằng nó trông tốt hơn so với sử dụng!(child is IContainer)

if (part is IContainer is false)
{
    return;
}

iscú pháp : expr is constant , trong đó expr là biểu thức để đánh giá và hằng số là giá trị để kiểm tra.


3
Tương tự bạn có thể làm if (part as IContainer is null). Thành thật không chắc cái nào tốt hơn.
Flynn1179

5

Xấu xí? Tôi không đồng ý. Cách duy nhất khác (cá nhân tôi nghĩ rằng điều này là "xấu hơn"):

var obj = child as IContainer;
if(obj == null)
{
   //child "aint" IContainer
}

@Mehrdad - Không thể? sẽ cho phép nó hoạt động, không nên sử dụng cái này. Đó chỉ là một ví dụ về một cách xấu hơn.
stevehipwell

@ Steveo3000: Có, nhưng bạn nên đề cập rõ ràng? là asmệnh đề. obj as intluôn luôn là một lỗi thời gian biên dịch.
Mehrdad Afshari

@Mehrdad - Đồng ý, BFree có thể chỉnh sửa bài đăng của mình để phản ánh điều này. Cho chúng tôi 'obj như int?'.
stevehipwell

@ Stevo3000: Tuy nhiên, tôi không nghĩ có gì sai với nó. IContainer cảm thấy giống như một giao diện hơn là loại giá trị. Chỉ muốn chỉ ra rằng nó đòi hỏi sự quan tâm về loại giá trị và không phải lúc nào cũng là bản dịch trực tiếp của ishình thức.
Mehrdad Afshari

bạn có thể tùy ý làm if (obj == default (IContainer)), sẽ chăm sóc các loại giá trị và loại tham chiếu
Joseph

3

Các isđánh giá lại hành đến một kết quả boolean, vì vậy bạn có thể làm bất cứ điều gì bạn nếu không sẽ có thể làm trên một bool. Để phủ nhận nó sử dụng !toán tử. Tại sao bạn muốn có một nhà điều hành khác chỉ cho việc này?


5
Nó không phải là một nhà điều hành khác. Tôi đã tự hỏi nếu có một từ khóa sẽ cho phép tôi bỏ thêm các parens. Đó là một lựa chọn chính, nhưng tôi tò mò.
Hugoware

Được rồi tôi hiểu rồi. Từ các ví dụ của bạn, tôi có ấn tượng rằng bạn đang tìm kiếm một nhà điều hành mới, chuyên dụng.
Brian Rasmussen

Tôi nghĩ rằng có một toán tử đặc biệt như vậy là xấu, bởi vì chúng ta sẽ có cách này (dù sao cũng đã giải thích điều này) và nếu chúng ta có một op khác, thì có hai cách để đạt được điều tương tự, có thể gây nhầm lẫn.
BuddhiP

3

Phương thức mở rộng IsNot<T>là một cách hay để mở rộng cú pháp. Ghi nhớ

var container = child as IContainer;
if(container != null)
{
  // do something w/ contianer
}

thực hiện tốt hơn là làm một cái gì đó như

if(child is IContainer)
{
  var container = child as IContainer;
  // do something w/ container
}

Trong trường hợp của bạn, nó không thành vấn đề khi bạn quay trở lại từ phương thức. Nói cách khác, hãy cẩn thận để không thực hiện cả việc kiểm tra loại và sau đó chuyển đổi loại ngay sau đó.


3

Mặc dù điều này không tránh được vấn đề về dấu ngoặc đơn, vì lợi ích của mọi người đến đây thông qua Google, nên đề cập rằng cú pháp mới hơn tồn tại (kể từ C # 7) để làm cho phần còn lại của mã của bạn sạch hơn một chút:

if (!(DocumentPart is IContainer container)) { return; }
foreach(DocumentPart child in container.Children) {
    ...

Điều này tránh được phép nhân đôi, kiểm tra null và có sẵn một biến trong phạm vi có thể là null.


2

Mặc dù toán tử IS thường là cách tốt nhất, có một giải pháp thay thế mà bạn có thể sử dụng trong một số trường hợp. Bạn có thể sử dụng toán tử như và kiểm tra null.

MyClass mc = foo as MyClass;
if ( mc == null ) { }
else {}

2

C # 9 (sẽ được phát hành với NET 5) sẽ bao gồm các mô hình logic and, ornot, cho phép chúng tôi viết những dòng này tao nhã hơn:

if (child is not IContainer) { ... }

Tương tự, mẫu này có thể được sử dụng để kiểm tra null:

if (child is not null) { ... }

Bạn có thể tìm thêm chi tiết về vấn đề Github theo dõi thay đổi này.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.