2009-08-31 29 views
13

Đây là thêm một 'tự hỏi tại sao' hơn là một vấn đề cụ thể nhưng nhìn vào đoạn mã sauTại sao ngầm gọi toString trên một loại giá trị gây ra một hướng dẫn hộp

 static void Main(string[] args) 
     { 
      int val = 10; 

      Console.WriteLine("val is {0}", val); // (1) 
      Console.WriteLine("val is {0}", val.ToString()); //(2) 


     } 

Trong trường hợp (1) IL Sau đây là sản lượng

IL_0000: nop 
    IL_0001: ldc.i4.s 10 
    IL_0003: stloc.0 
    IL_0004: ldstr  "val is {0}" 
    IL_0009: ldloc.0 
    IL_000a: box  [mscorlib]System.Int32 
    IL_000f: call  void [mscorlib]System.Console::WriteLine(string, 
                   object) 

trong trường hợp (2), nơi tôi một cách rõ ràng gọi phương thức toString tôi nhận được

IL_0014: nop 
    IL_0015: ldstr  "val is {0}" 
    IL_001a: ldloca.s val 
    IL_001c: call  instance string [mscorlib]System.Int32::ToString() 
    IL_0021: call  void [mscorlib]System.Console::WriteLine(string, 
                   object) 

Vì vậy, trong trường hợp (1), mặc dù int ghi đè toString, kiểu giá trị được đóng hộp và phương thức toString được gọi mà có lẽ sau đó gọi ghi đè vtable

Vì vậy, kết quả là giống hệt nhau nhưng một toString rõ ràng tránh một hoạt động đấm bốc

Có ai biết tại sao không?

= Edit =
OK để rõ ràng, những gì gây nhầm lẫn cho tôi là tôi bắt đầu với giả định rằng mặc dù int xuất phát từ System.ValueType, do đó có nguồn gốc từ System.Object vì nó chứa toString, GetHashCode Vì vậy, trong quan điểm ngây thơ của tôi (có lẽ từ C + +), nếu tôi ghi đè lên một phương pháp có nguồn gốc từ System.Object sau đó không có nhu cầu để đúc vào System.Object (và do đó hộp kiểu giá trị) vì một phương pháp overriden tồn tại và trình biên dịch sẽ tự động tham chiếu mục nhập vtable cho loại.
Tôi cũng giả định rằng việc gọi Console.WriteLine() hoàn toàn gọi int.toString vì vậy có lẽ đó là nơi tôi sẽ sai. Hy vọng có ý nghĩa

OK - tất cả được sắp xếp. Cảm ơn tất cả vì đã đặt tôi thẳng. Tất cả để làm với một giả định xấu của tôi rằng Console.WriteLine đã làm một chuyển đổi chuỗi ngầm định. Đừng hỏi tôi lý do tại sao tôi nghĩ rằng - có vẻ như hiển nhiên không rõ ràng hiện giờ đã sai như thế nào :)

Trả lời

12

Bạn hoàn toàn không gọi số ToString. Không phải là quá tải của phương thức WriteLine có chuỗi sau chuỗi định dạng, nó chỉ lấy các đối tượng.

Vì vậy, bạn không hoàn toàn gọi số ToString, bạn đang chuyển đổi hoàn toàn int thành object. Trường hợp đầu tiên tương đương với:

Console.WriteLine("val is {0}", (object)val); 

Vì loại int là loại giá trị, quyền anh xảy ra.

Trường hợp thứ hai là tương đương với:

Console.WriteLine("val is {0}", (object)val.ToString()); 

Như chuỗi là một loại tài liệu tham khảo, đúc nó để đối tượng không thực sự gây bất kỳ mã được phát ra. Nó chỉ phù hợp với loại có chữ ký phương thức.

+0

Vâng, đó là nơi tôi đang đi sai. Tôi giả sử có một diễn viên tiềm ẩn xảy ra. Làm cho tinh thần ngay bây giờ! – zebrabox

4

Vì trong trường hợp đầu tiên, bạn chuyển số int làm object khi gọi hàm Console.WriteLine(). Điều này buộc int được đóng hộp. Trong phương pháp thứ hai, bạn gọi trực tiếp ToString, tránh boxing và chuyển một số string đến WriteLine, đã là loại tham chiếu.

+0

Nhưng tại sao không khi int cung cấp ghi đè rõ ràng để chứa mục nhập vtable cho phương thức toString? – zebrabox

+0

@zebra: Tôi không chắc bạn đang hỏi gì. Một lần nữa, hoạt động boxing diễn ra bởi vì int phải được tham chiếu như một đối tượng. Điều này không xảy ra trong ví dụ thứ hai vì một chuỗi đang được chuyển tới WriteLine, không phải là một int. –

+0

@Adam. Đó là OK, tất cả các bản lề trên một giả định xấu của tôi rằng một chuyển đổi toString tiềm ẩn đã xảy ra. Bây giờ tôi biết điều đó không đúng, tất cả đều rõ ràng một lần nữa. Nếu Console.WriteLine chấp nhận một đối tượng thì hộp phải xuất hiện khi Jared Par cho biết để đáp ứng các tham số phương thức – zebrabox

2

Trong cuộc gọi đầu tiên, không có lệnh gọi .ToString nào cả. Thay vào đó, bạn đang gọi hàm Console.WriteLine (đối tượng). Tham số đầu tiên là kiểu int và phải được đóng hộp để thỏa mãn đối tượng kiểu. Sau đó bên trong của WriteLite,. ToString sẽ được gọi trên đối tượng.

+0

Đúng. Lỗi của tôi. Giả định ngu ngốc của tôi - tất cả rõ ràng bây giờ. Chúc mừng :) – zebrabox

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