2009-02-27 61 views
34

Ai đó có thể làm rõ từ khóa C# is vui lòng. Cụ thể là 2 câu hỏi sau:Tại sao "int [] là uint [] == true" trong C#

Q1) dòng 5; Tại sao điều này trở lại đúng?

Q2) dòng 7; Tại sao không có ngoại lệ cast?

public void Test() 
{ 
    object intArray = new int[] { -100, -200 };    

    if (intArray is uint[]) //why does this return true? 
    { 
     uint[] uintArray = (uint[])intArray; //why no class cast exception? 

     for (int x = 0; x < uintArray.Length; x++) 
     { 
      Console.Out.WriteLine(uintArray[x]); 
     } 
    } 
} 

Mô tả của MSDN không làm rõ tình hình. Nó tuyên bố rằng is sẽ trả về true nếu một trong các điều kiện này được đáp ứng. (Http://msdn.microsoft.com/en-us/library/scekt9xw(VS.71).aspx>MDSN Điều)

 
expression is not null. 
expression can be cast to type. 

Tôi không tin rằng bạn có thể làm một dàn diễn viên hợp lệ int [] thành uint []. Bởi vì:

A) Mã này không biên dịch:

int[] signed = new int[] { -100 }; 
uint[] unsigned = (uint[])signed; 

B) Làm các diễn viên trong chương trình gỡ rối cho một lỗi:

(uint[])signed 
"Cannot convert type 'int[]' to 'uint[]'" 

Chắc chắn, nếu dòng 3 là int [] thay vì đối tượng thì nó sẽ không bao giờ biên dịch. Điều này đưa tôi đến câu hỏi cuối cùng liên quan đến quý 2.

Q3) Tại sao C# tăng lỗi truyền/chuyển đổi trong trình gỡ rối và trình biên dịch nhưng không phải lúc chạy?

+2

Eric Lippert ở đâu khi bạn cần anh ấy? –

+4

Sai, đây là Stack Overflow, bạn có nghĩa là "Jon Skeet ở đâu khi bạn cần anh ấy?" ;) – Ash

+0

Kiểm tra câu trả lời của tôi, tôi đã cập nhật liên kết tới video mà tôi nghĩ giải thích vấn đề cơ bản. Kiểm tra nó ra! –

Trả lời

34

C# và CLR có quy tắc chuyển đổi hơi khác.

Bạn có thể không trực tiếp cast giữa int[]uint[] trong C# vì ngôn ngữ không tin bất kỳ chuyển đổi có sẵn. Tuy nhiên, nếu bạn đi qua kết quả object thì kết quả là CLI. Từ phần CLI đặc tả 8,7 (Tôi hy vọng - Tôi trích dẫn một email exchange I had on this topic with Eric Lippert một thời gian trước):

Signed and unsigned integral primitive types can be assigned to each other; e.g., int8 := uint8 is valid. For this purpose, bool shall be considered compatible with uint8 and vice versa, which makes bool := uint8 valid, and vice versa. This is also true for arrays of signed and unsigned integral primitive types of the same size; e.g., int32[] := uint32[] is valid.

(Tôi đã không được chọn, nhưng tôi cho rằng loại này của kiểu tham chiếu chuyển đổi là hợp lệ là những gì làm is cũng trả lại đúng.)

Thật không may là có ngắt kết nối giữa ngôn ngữ và công cụ thực thi cơ bản, nhưng nó không thể tránh khỏi trong thời gian dài, tôi nghi ngờ. Có một số trường hợp khác như thế này, nhưng tin tốt là họ hiếm khi có vẻ gây hại đáng kể.

EDIT: Khi Marc xóa câu trả lời của mình, tôi đã liên kết với thư đầy đủ từ Eric, như được đăng lên nhóm tin C#.

+0

giống như một ứng cử viên khác cho câu hỏi "bạn có thể làm gì trong MSIL bạn không thể trong câu hỏi C#". trực tiếp convesion mà không cần phải messabout với một đối tượng/biến Array để xoa dịu C# compiler – ShuggyCoUk

+0

@ShuggyCoUk: Good call - sẽ cập nhật câu trả lời của tôi, liên kết đến câu hỏi này. –

+1

mind = blown ... – Mehrdad

1

Góp ý:

Tuyên bố intArray là "int [] intArray" hơn sau đó "đối tượng intArray" sẽ cho phép trình biên dịch để nhận người tàn tật C# đúc. Trừ khi bạn hoàn toàn phải sử dụng đối tượng, tôi sẽ sử dụng phương pháp đó.

Re Q2, Q3:

Khi chạy Bạn đã thử gói các diễn viên trong một khối checked?

Từ bài viết này tại MSDN:

By default, an expression that contains only constant values causes a compiler error if the expression produces a value that is outside the range of the destination type. If the expression contains one or more non-constant values, the compiler does not detect the overflow.

...

By default, these non-constant expressions are not checked for overflow at run time either, and they do not raise overflow exceptions. The previous example displays -2,147,483,639 as the sum of two positive integers.

Overflow checking can be enabled by compiler options, environment configuration, or use of the checked keyword.

Như nó nói, bạn có thể thực thi kiểm tra tràn hơn trên toàn cầu thông qua một môi trường biên dịch hoặc cấu hình môi trường.

Trong trường hợp của bạn, điều này có thể gây ra lỗi khi chạy sẽ đảm bảo số không dấu không hợp lệ có thể bị tràn số đã ký sẽ không xảy ra âm thầm.

[Cập nhật] Sau khi kiểm tra mã này, tôi thấy rằng việc sử dụng khai báo đối tượng kiểu thay vì int [] xuất hiện để vượt qua tiêu chuẩn C# đúc sytax, bất kể có được bật hay không.

Như JS đã nói, khi bạn sử dụng đối tượng, bạn bị ràng buộc bởi quy tắc CLI và những điều này dường như cho phép điều này xảy ra.

Re Q1:

Điều này liên quan đến những điều trên. Trong ngắn hạn, bởi vì các diễn viên tham gia nó không ném một ngoại lệ (dựa trên thiết lập tràn hiện tại). Cho dù đây là một ý tưởng hay là một câu hỏi khác.

From MSDN:

An "is" expression evaluates to true if the provided expression is non-null, and the provided object can be cast to the provided type without causing an exception to be thrown.

+0

Nhưng nó không trả lời câu hỏi đầu tiên của mình, "tại sao (intArray là uint []) " –

+0

Không, kiểm tra không bắt được điều này, đáng ngạc nhiên. Trình gỡ lỗi hoàn toàn bị nhầm lẫn bởi các nội dung (chỉ hiển thị? Cho các phần tử trong thanh tra), và nhận được giá trị ngoài nhận được giá trị được bao bọc. –

+0

Hành vi tương tự trong thử nghiệm của tôi. Jon Skeet đâu rồi khi anh cần anh ta? – Ash

0

Tôi đoán ngược compatablility với NET 1: Tôi vẫn còn một chút mờ về các chi tiết, nhưng tôi tin rằng kiểu CLR của tất cả các mảng chỉ đơn giản là System.Array, với các thuộc tính Kiểu bổ sung để tra cứu loại phần tử. 'là' có lẽ chỉ không tính đến điều đó trong CLR v1, và bây giờ phải duy trì điều đó.

Nó không hoạt động trong trường hợp (uint[])(new int[]{}) có lẽ là do trình biên dịch C# (không phải thời gian chạy CLR) có thể thực hiện kiểm tra chặt chẽ hơn.

Ngoài ra, mảng được chỉ cần gõ không an toàn nói chung:

Animal[] tigers = new Tiger[10]; 
tigers[3] = new Elephant(); // ArrayTypeMismatchException 
0

OK,

Tôi cố gắng thực hiện việc này.

Trước hết, tài liệu nói, "Kiểm tra xem một đối tượng có tương thích với một loại nhất định không.", Nó cũng nói rằng NẾU loại bên trái là "có thể truyền" (bạn có thể chuyển đổi không có ngoại lệ) thành loại bên phải và biểu thức đánh giá thành không null, từ khóa "is" sẽ đánh giá là true.

Tìm Jon Skeet để tìm câu trả lời khác. Anh ấy nói nó hùng hồn hơn tôi có thể. Anh ấy đúng, nếu một chuyển đổi có sẵn, nó sẽ chấp nhận cú pháp của bạn, sau đó bạn có thể viết cú pháp của riêng mình, nhưng nó có vẻ quá mức cần thiết trong tình huống này.

Tham chiếu: http://msdn.microsoft.com/en-us/library/scekt9xw(VS.80).aspx

4

Thật thú vị. Tôi tìm thấy điều này trong tiêu chuẩn ECMA-335. 4.3 castclass. Lưu ý rằng:

  • Mảng kế thừa từ System.Array.

  • Nếu Foo có thể truyền sang Bar, khi đó Foo [] có thể truyền sang Bar [].

  • Vì mục đích ghi chú 2 ở trên, enums được coi là loại cơ bản của chúng: vì vậy E1 [] có thể được truyền sang E2 [] nếu E1 và E2 chia sẻ một loại cơ bản.

Bạn có thể truyền int đến uint, nhưng nó hoạt động như thế này rất lạ. Visual Studio không nhận ra bất kỳ điều này, ngay cả đồng hồ, khi trình gỡ lỗi được đính kèm chỉ hiển thị một dấu chấm hỏi '?'.

Bạn có thể muốn xem this, tua đi khoảng 10 phút và lắng nghe Anders giải thích việc triển khai mảng đồng biến thể. Tôi nghĩ đó là vấn đề cơ bản ở đây.

Các vấn đề liên quan