2010-01-11 30 views
17

Tôi đang vật lộn với một điều kỳ lạ, ít nhất là đối với tôi, phương pháp quá tải độ phân giải của .net. Tôi đã viết một mẫu nhỏ mô phỏng vấn đề:Cách xử lý quá tải có độ phân giải hành vi bất ngờ

class Program 
{ 
    static void Main(string[] args) 
    { 
     var test = new OverloadTest(); 
     test.Execute(0); 
     test.Execute(1); 

     Console.ReadLine(); 
    } 
} 

public class OverloadTest 
{ 
    public void Execute(object value) 
    { 
     Console.WriteLine("object overload: {0}", value); 
    } 

    public void Execute(MyEnum value) 
    { 
     Console.WriteLine("enum overload: {0}", value); 
    } 
} 

public enum MyEnum 
{ 
    First = 1, Second = 2, Third = 3 
} 

Sẽ in:

enum overload: 0 
object overload: 1 

Về cơ bản sự quá tải gọi là khác nhau tùy thuộc vào giá trị (0, 1) thay vì kiểu dữ liệu nhất định .

Ai đó có thể giải thích?

Cập nhật

tôi nên đã chỉ ra rằng có một hành vi khác nhau giữa C# 2 và C# 3

Do((long)0) => object overload //C# 2 
Do((long)0) => enum overload //C# 3 

Trả lời

16

Có - hằng số 0 là ngầm chuyển đổi thành bất kỳ loại enum. Hằng số 1 chỉ là rõ ràng là có thể chuyển đổi thành loại enum. Cả hai đều được chuyển đổi hoàn toàn thành object (thông qua quyền anh) nhưng chuyển đổi thành enum được ưu tiên hơn khi có sẵn.

Lưu ý rằng điều này có không có gì để làm với các giá trị mà enum xác định. Việc chuyển đổi cho bất kỳ giá trị khác không là rõ ràng cho dù nó phù hợp với một giá trị trong enum hay không. Nó chỉ là một trường hợp đặc biệt cho giá trị 0, mà làm cho một số mã khác đơn giản hơn (đặc biệt là khi giao dịch với cờ). Tôi không có thông số kỹ thuật để tìm tài liệu tham khảo, tôi sợ.

Sự kỳ lạ về tiền thưởng: do lỗi trong trình biên dịch MS (không bao giờ được sửa - nó sẽ phá vỡ tính tương thích ngược) thực ra là various zero constants, không chỉ là số nguyên. Vì vậy, Execute(0d)Execute(0m) cũng sẽ chuyển đổi số double và số thập phân thành enum. Nó không hoạt động cho mỗi không đổi - nó phụ thuộc vào bản chất chính xác của mã nguồn. Đó là tất cả rất kỳ lạ - theo liên kết nơi Eric Lippert tiết lộ tất cả ...

+0

Điều đó rất lạ. Tôi đã mong đợi nó sẽ không biên dịch chút nào, bởi vì hai cuộc gọi riêng biệt tới Execute là mơ hồ. 0 và 1 là int's, và vì vậy nó có giá trị như nhau để gọi quá tải đối tượng cũng như quá tải MyEnum. – Nick

+0

tôi không biết điều đó. tại sao 0 chuyển đổi hoàn toàn thành bất kỳ loại enum nào? trong ví dụ ở đây, 0 không phải là giá trị hợp lệ. nếu một cái gì đó không có ý nghĩa với dòng suy nghĩ của tôi, điều đó không nhất thiết có nghĩa là tất cả những gì nhiều (như được chỉ ra 1 phút trước);) – hackerhasid

+0

@statichippo: Nó tiện dụng trong một vài trường hợp, chẳng hạn như sau khi thực hiện số học bitwise trên cờ. @Nick: Cả hai phương pháp đều * áp dụng *, nhưng chuyển đổi từ 0 thành enum là "tốt hơn" chuyển đổi từ 0 thành đối tượng theo các quy tắc của C# spec ... đó là lý do tại sao quá tải đó được gọi. –

-1

Một Enum chỉ là ánh xạ tới một int (theo mặc định). 0 không ánh xạ tới Enum của bạn để quá tải mà một đối tượng được sử dụng. 1 bản đồ để enum của bạn để quá tải Enum được sử dụng.

Bạn có thể làm điều này:

Execute((object) 1); 

để đầu ra

quá tải đối tượng: 1

+2

Dường như kết quả thực sự là trái ngược với những gì bạn mong muốn. Quá tải enum là nhận được hit cho 0 và không cho 1. – mkedobbs

+0

Tôi chỉ cần đi qua này và nhận ra tôi đã đọc sai bài viết. Tôi nghĩ rằng 0 được gọi là "đối tượng" và 1 đã được gọi là "enum". Tôi sẽ phải xem xét điều này bởi vì _that_ không có ý nghĩa nhiều! – hackerhasid

+0

@statichippo: Nó có ý nghĩa hoàn hảo khi bạn nhìn vào thông số kỹ thuật và chuyển đổi có sẵn :) –

0

Tôi đồng ý với câu trả lời của Jon Skeet - tham khảo bài đăng của anh ấy (ở trên) vào ngày 11 tháng 1 lúc 17:32. Tiếp tục mở rộng, vui lòng tham khảo C# ngôn ngữ đặc tả - Trang: 110

6.1.3 Implicit chuyển đổi liệt kê Một chuyển đổi liệt kê ngầm phép số thập phân-nguyên-đen từ 0 đến được chuyển đổi sang bất kỳ enum loại và với bất kỳ kiểu nullable nào có kiểu cơ bản là kiểu enum. Trong trường hợp thứ hai, chuyển đổi được đánh giá bằng cách chuyển đổi thành kiểu enum cơ bản và gói kết quả (§4.1.10).

Tuy nhiên có một vấn đề:

thêm các tuyên bố:

test.Execute (-0,0); // đối tượng quá tải: 0

trong khi thêm các mục sau:

test.Execute (+0.0); // enum quá tải: 0

Jacques Colmenero Enterprise Architect [email protected]

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