2012-06-18 19 views
24

Tôi tò mò muốn biết tại sao trình biên dịch C# chỉ cung cấp cho tôi thông báo lỗi cho câu lệnh if thứ hai.Toán tử ">" không thể áp dụng cho loại 'ulong' và 'int'

enum Permissions : ulong 
{ 
    ViewListItems = 1L, 
} 

public void Method() 
{ 
    int mask = 138612833; 
    int compare = 32; 

    if (mask > 0 & (ulong)Permissions.ViewListItems > 32) 
    { 
     //Works 
    } 

    if (mask > 0 & (ulong)Permissions.ViewListItems > compare) 
    { 
     //Operator '>' cannot be applied to operands of type 'ulong' and 'int' 
    } 
} 
+1

Lý do cho lỗi này là rõ ràng. Trong ví dụ thứ hai bạn đang cố gắng thực hiện một hoạt động bất hợp pháp với một số nguyên. Trong ví dụ đầu tiên, '32' đang được coi là' ulong'. Bạn thực sự nên tạo 'mask' là' ulong'. –

+0

@Ramhound Hoặc là (làm 'so sánh' một 'ulong'), hoặc tạo' so sánh' một biến 'const', vì vậy' const int compare = 32; '. Các biểu thức liên tục sẽ chuyển đổi tự động một cách hạnh phúc từ 'int' thành' ulong' tại thời gian biên dịch nếu chúng không âm, một cái gì đó nằm dưới tên _Implicit constant expression conversion_. –

Trả lời

30

Tôi đã thử nghiệm điều này, sử dụng ILSpy để kiểm tra đầu ra và đây là những gì tôi đã khám phá.

Rõ ràng trong trường hợp thứ hai của bạn đây là lỗi - bạn không thể so sánh ulongint vì không có loại nào bạn có thể ép buộc cả hai. A ulong có thể quá lớn đối với số longint có thể âm.

Trong trường hợp đầu tiên, trình biên dịch đang được thông minh. Nó nhận ra rằng const 1> const 32 là không bao giờ đúng, và không bao gồm tuyên bố if của bạn trong đầu ra biên dịch cả. (Nó sẽ đưa ra một cảnh báo cho mã không thể truy cập.) Nó giống nhau nếu bạn xác định và sử dụng một số const int thay vì chữ, hoặc thậm chí nếu bạn đúc một cách rõ ràng (nghĩa là (int)32).

Nhưng sau đó không phải là trình biên dịch so sánh thành công số ulong với số int mà chúng tôi vừa nói là không thể?

Dường như không. Vì vậy, những gì đang diễn ra?

Hãy thử thay vì làm điều gì đó dọc theo các dòng sau. (Lấy đầu vào và đầu ra bằng văn bản để trình biên dịch không biên dịch bất cứ điều gì đi.)

const int thirtytwo = 32; 
static void Main(string[] args) 
{ 
    ulong x = ulong.Parse(Console.ReadLine()); 
    bool gt = x > thirtytwo; 
    Console.WriteLine(gt); 
} 

này sẽ biên dịch, mặc dù ulong là một biến, và mặc dù kết quả là không biết đến lúc biên dịch. Hãy nhìn vào sản lượng trong ILSpy:

private static void Main(string[] args) 
{ 
    ulong x = ulong.Parse(Console.ReadLine()); 
    bool gt = x > 32uL;  /* Oh look, a ulong. */ 
    Console.WriteLine(gt); 
} 

Vì vậy, trình biên dịch là trong thực tế điều trị của bạn const int như một ulong. Nếu bạn thực hiện thirtytwo = -1, mã không thể biên dịch được, mặc dù sau đó chúng tôi biết rằng gt sẽ luôn là là đúng. Bản thân trình biên dịch không thể so sánh một số ulong với một số int.

Cũng lưu ý rằng nếu bạn thực hiện x một long thay vì một ulong, trình biên dịch tạo ra 32L hơn 32 là một số nguyên, mặc dù nó không tới. (Bạn có thể so sánh một intlong khi chạy.)

điểm này để trình biên dịch không điều trị 32 như một ulong trong trường hợp đầu tiên bởi vì nó đến, chỉ vì nó thể phù hợp với loại x . Nó tiết kiệm thời gian chạy từ việc phải ép buộc hằng số, và đây chỉ là tiền thưởng khi cưỡng chế nên bởi các quyền không thể thực hiện được.

+1

Đây là một cuốn sách rất thú vị, đạo cụ cho bạn để nghiên cứu. – Amicable

+1

@Amicable - đạo cụ cho _you_ cho một câu hỏi thú vị khiến tôi muốn nghiên cứu nó :) – Rawling

+0

Trình biên dịch C# hoàn toàn phù hợp với Đặc tả ngôn ngữ C# tại đây. Khi một biểu thức của kiểu 'int' là một hằng số biên dịch-thời gian, có tồn tại một [ẩn biểu thức liên tục chuyển đổi] (http://msdn.microsoft.com/en-us/library/aa691286.aspx) từ' int' để 'ulong' _provided rằng giá trị nằm trong phạm vi_ của' ulong', tức là không âm, cái mà trình biên dịch C# có thể thấy với một biểu thức không đổi. '32' là một biểu thức liên tục của kiểu' int'. Khi một biểu thức kiểu 'int' là _not_ một hằng số biên dịch, không có chuyển đổi ngầm nào tồn tại thành' ulong'. Ví dụ 'so sánh'. –

21

Nó không phải là CLR đưa ra thông báo lỗi này là trình biên dịch.

Trong ví dụ đầu tiên của bạn đối xử với trình biên dịch 32 như ulong (hoặc một loại đó là mặc nhiên chuyển đổi thành ulong ví dụ uint) trong khi trong ví dụ thứ hai của bạn, bạn đã khai báo rõ ràng kiểu như một int. Không có quá tải của nhà điều hành > chấp nhận ulongint và do đó bạn gặp lỗi trình biên dịch.

+7

Trang nguyên văn bản (http://msdn.microsoft.com/en-us/library/aa664674.aspx) nói "Nếu chữ không có hậu tố, nó có loại đầu tiên trong số các loại này, trong đó giá trị của nó có thể được biểu diễn: int, uint, long, ulong. " Cộng với Intellisense của tôi (tooltip) nói rằng '32' là một' int'. Nhưng điều này dường như là những gì đang xảy ra ... – Rawling

+1

@Rawling Rất đúng, tôi có thể thấy ba lý do có thể xảy ra (tôi dám nói nhiều hơn nữa): # 1 có lẽ vì các giải thích khác nhau về "giá trị có thể được biểu diễn", tức là trình biên dịch biết rằng 32 không thể là một int vì mã sẽ không biên dịch và thử uint tiếp theo thành công. Intellisense rõ ràng không đánh giá toàn bộ biểu thức để tính toán loại, int nói chung là chính xác vậy tại sao hy sinh thời gian tính toán cho một trường hợp cạnh. # 2 tài liệu cho các số nguyên nguyên là lỗi thời. HoặC# 3 đó là lỗi trình biên dịch. –

+0

@Rawling - Không có lỗi nào đang hoạt động chính xác như mong muốn. Chữ '32' theo nghĩa đen được coi là' long'. Bạn thậm chí còn trích dẫn lời tuyên bố nơi nó nói rằng nó sẽ được coi là một 'long'. –

3

câu trả lời của rich.okelly và rawling là chính xác vì sao bạn không thể so sánh chúng trực tiếp. Bạn có thể sử dụng phương thức ToUInt64 của lớp học để quảng bá int.

if (mask > 0 & (ulong)Permissions.ViewListItems > Convert.ToUInt64(compare)) 
{ 
} 
Các vấn đề liên quan