Helpex - Trao đổi & giúp đỡ Đăng nhập
111

Tôi nhận thấy rằng Resharper gợi ý rằng tôi nên chuyển điều này:

if (myObj.myProp is MyType)
{
   ...
}

vào cái này:

var myObjRef = myObj.myProp as MyType;
if (myObjRef != null)
{
   ...
}

Tại sao nó sẽ đề xuất sự thay đổi này? Tôi đã quen với việc Resharper đề xuất các thay đổi tối ưu hóa và thay đổi giảm mã, nhưng điều này có vẻ như nó muốn lấy một câu lệnh duy nhất của tôi và biến nó thành một dấu hai dòng.

Theo MSDN :

Một biểu hiện đánh giá lại là true nếu cả hai điều kiện sau đây được đáp ứng:

biểu thức không rỗng. biểu thức có thể được ép kiểu . Nghĩa là, một biểu thức ép kiểu của biểu mẫu (type)(expression)sẽ hoàn thành mà không có ngoại lệ.

Có phải tôi đã đọc sai điều đó hay không isthực hiện các kiểm tra giống hệt nhau, chỉ trong một dòng đơn lẻ mà không cần phải tạo rõ ràng một biến cục bộ khác cho kiểm tra rỗng?

111 hữu ích 1 bình luận 53k xem chia sẻ
155

Bởi vì chỉ có một dàn diễn viên. So sánh cái này:

if (myObj.myProp is MyType) // cast #1
{
    var myObjRef = (MyType)myObj.myProp; // needs to be cast a second time
                                         // before using it as a MyType
    ...
}

đến điều này:

var myObjRef = myObj.myProp as MyType; // only one cast
if (myObjRef != null)
{
    // myObjRef is already MyType and doesn't need to be cast again
    ...
}

C # 7.0 hỗ trợ cú pháp nhỏ gọn hơn bằng cách sử dụng đối sánh mẫu :

if (myObj.myProp is MyType myObjRef)
{
    ...
}
155 hữu ích 5 bình luận chia sẻ
12

Tùy chọn tốt nhất là sử dụng đối sánh mẫu như vậy:

if (value is MyType casted){
    //Code with casted as MyType
    //value is still the same
}
//Note: casted can be used outside (after) the 'if' scope, too
12 hữu ích 2 bình luận chia sẻ
6

Vẫn chưa có thông tin về những gì thực sự xảy ra bên dưới vành đai. Hãy xem ví dụ này:

object o = "test";
if (o is string)
{
    var x = (string) o;
}

Điều này chuyển thành IL sau:

IL_0000:  nop         
IL_0001:  ldstr       "test"
IL_0006:  stloc.0     // o
IL_0007:  ldloc.0     // o
IL_0008:  isinst      System.String
IL_000D:  ldnull      
IL_000E:  cgt.un      
IL_0010:  stloc.1     
IL_0011:  ldloc.1     
IL_0012:  brfalse.s   IL_001D
IL_0014:  nop         
IL_0015:  ldloc.0     // o
IL_0016:  castclass   System.String
IL_001B:  stloc.2     // x
IL_001C:  nop         
IL_001D:  ret   

Điều quan trọng ở đây là cuộc gọi isinstcastclasscuộc gọi - cả hai đều tương đối đắt tiền. Nếu bạn so sánh nó với giải pháp thay thế, bạn có thể thấy nó chỉ isinstkiểm tra:

object o = "test";
var oAsString = o as string;
if (oAsString != null)
{

}

IL_0000:  nop         
IL_0001:  ldstr       "test"
IL_0006:  stloc.0     // o
IL_0007:  ldloc.0     // o
IL_0008:  isinst      System.String
IL_000D:  stloc.1     // oAsString
IL_000E:  ldloc.1     // oAsString
IL_000F:  ldnull      
IL_0010:  cgt.un      
IL_0012:  stloc.2     
IL_0013:  ldloc.2     
IL_0014:  brfalse.s   IL_0018
IL_0016:  nop         
IL_0017:  nop         
IL_0018:  ret  

Cũng đáng nói là một loại giá trị sẽ sử dụng unbox.anythay vì castclass:

object o = 5;
if (o is int)
{
    var x = (int)o;
}

IL_0000:  nop         
IL_0001:  ldc.i4.5    
IL_0002:  box         System.Int32
IL_0007:  stloc.0     // o
IL_0008:  ldloc.0     // o
IL_0009:  isinst      System.Int32
IL_000E:  ldnull      
IL_000F:  cgt.un      
IL_0011:  stloc.1     
IL_0012:  ldloc.1     
IL_0013:  brfalse.s   IL_001E
IL_0015:  nop         
IL_0016:  ldloc.0     // o
IL_0017:  unbox.any   System.Int32
IL_001C:  stloc.2     // x
IL_001D:  nop         
IL_001E:  ret   

Tuy nhiên, lưu ý rằng điều này không nhất thiết phải chuyển thành kết quả nhanh hơn như chúng ta có thể thấy ở đây . Mặc dù vậy, dường như đã có những cải tiến kể từ khi câu hỏi đó được đặt ra: phôi dường như được thực hiện nhanh như trước đây nhưng aslinqhiện nhanh hơn khoảng 3 lần.

6 hữu ích 0 bình luận chia sẻ
4

Cảnh báo về trình sạc lại:

"Type check and direct cast can be replaced with try cast and check for null"

Cả hai đều sẽ hoạt động, nó phụ thuộc vào cách mã của bạn phù hợp với bạn hơn. Trong trường hợp của tôi, tôi chỉ bỏ qua cảnh báo đó:

//1st way is n+1 times of casting
if (x is A) ((A)x).Run();
else if (x is B) ((B)x).Run();
else if (x is C) ((C)x).Run();
else if (x is D) ((D)x).Run();
//...
else if (x is N) ((N)x).Run();    
//...
else if (x is Z) ((Z)x).Run();

//2nd way is z times of casting
var a = x as Type A;
var b = x as Type B;
var c = x as Type C;
//..
var n = x as Type N;
//..
var z = x as Type Z;
if (a != null) a.Run();
elseif (b != null) b.Run();
elseif (c != null) c.Run();
...
elseif (n != null) n.Run();
...
elseif (x != null) x.Run();

Theo cách thứ 2, mã của tôi dài hơn và hiệu suất kém hơn.

4 hữu ích 1 bình luận chia sẻ
3

Đối với tôi, điều này có vẻ phụ thuộc vào khả năng xảy ra là nó có thuộc loại đó hay không. Chắc chắn sẽ hiệu quả hơn nếu thực hiện ép kiểu trước nếu đối tượng thuộc loại đó trong hầu hết thời gian. Nếu nó chỉ thỉnh thoảng thuộc loại đó thì việc kiểm tra trước có thể là tối ưu hơn.

Chi phí tạo ra một biến cục bộ là rất không đáng kể so với chi phí của việc kiểm tra kiểu.

Tính dễ đọc và phạm vi là những yếu tố quan trọng hơn đối với tôi. Tôi không đồng ý với ReSharper và chỉ sử dụng toán tử "is" vì lý do đó; tối ưu hóa sau nếu đây là một nút cổ chai thực sự.

(Tôi giả định rằng bạn chỉ sử dụng myObj.myProp is MyTypemột lần trong chức năng này)

3 hữu ích 0 bình luận chia sẻ
1

Tôi muốn nói điều này là để tạo một phiên bản được đánh máy mạnh của myObj.myProp, đó là myObjRef. Điều này sau đó sẽ được sử dụng khi bạn đang tham chiếu giá trị này trong khối, thay vì phải thực hiện ép kiểu.

Ví dụ, điều này:

myObjRef.SomeProperty

tốt hơn thế này:

((MyType)myObj.myProp).SomeProperty
1 hữu ích 0 bình luận chia sẻ
0

Nó cũng nên đề xuất một thay đổi thứ hai:

(MyType)myObj.myProp

thành

myObjRef

Điều này tiết kiệm một quyền truy cập thuộc tính và một diễn viên, so với mã gốc. Nhưng nó chỉ có thể sau khi thay đổi isthành as.

0 hữu ích 5 bình luận chia sẻ
loading
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ẻ c# .net casting resharper , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading