Sự khác biệt giữa ref và out trong thời gian chạy là gì?


15

C # cung cấp refouttừ khóa để làm cho các đối số được truyền bằng tham chiếu. Ngữ nghĩa của hai là rất giống nhau. Sự khác biệt duy nhất là trong việc khởi tạo biến flaged:

  • refyêu cầu biến phải được khởi tạo trước khi chuyển nó vào hàm, outkhông.
  • outyêu cầu biến được khởi tạo bên trong hàm, refkhông.

Các trường hợp sử dụng của hai từ khóa này cũng gần như giống nhau và việc sử dụng quá thường xuyên của chúng là tôi tin rằng nó có mùi mã (mặc dù có các trường hợp sử dụng hợp lệ như TryParseTryGetValuemẫu).

Bởi vì điều này ai đó có thể giải thích, tại sao có hai công cụ rất giống nhau trong C # cho các trường hợp sử dụng hẹp như vậy?

Ngoài ra, trên MSDN , có tuyên bố rằng họ có hành vi thời gian chạy khác nhau:

Mặc dù các từ khóa ref và out gây ra hành vi thời gian chạy khác nhau, chúng không được coi là một phần của chữ ký phương thức tại thời điểm biên dịch.

Hành vi thời gian chạy của họ khác nhau như thế nào?

Phần kết luận

Cả hai câu trả lời đều đúng, cảm ơn cả hai. Tôi chấp nhận jmoreno vì nó rõ ràng hơn.


Tôi đoán là cả hai đều được thực hiện theo cùng một cách như reftrong C ++; để trỏ đến con trỏ đối tượng (hoặc nguyên thủy) trong câu hỏi. tức là Int32.TryParse(myStr, out myInt)(C #) được "thực thi" giống như int32_tryParse(myStr, &myInt)(C); sự khác biệt duy nhất là một số ràng buộc được thực thi bởi trình biên dịch để ngăn ngừa lỗi. (Tôi sẽ không đăng bài này như một câu trả lời vì tôi có thể sai về cách thức hoạt động này đằng sau hậu trường, nhưng đây là cách tôi hình dung nó hoạt động [bởi vì nó làm cho tinh thần])
Cole Johnson

Câu trả lời:


10

Tại thời điểm câu hỏi này được hỏi, bài viết MSDN không chính xác (nó đã được sửa chữa ). Thay vì "gây ra hành vi khác nhau" thì nên "yêu cầu hành vi khác".

Cụ thể, trình biên dịch thực thi các yêu cầu khác nhau cho hai từ khóa, mặc dù cùng một mecanism (IL) được sử dụng để cho phép hành vi.


Vì vậy, sự hiểu biết của tôi là trình biên dịch kiểm tra những thứ như hủy bỏ outtham số hoặc không gán reftham số, nhưng IL mà nó phát ra chỉ là một tham chiếu. Đúng không?
Andrew nói Phục hồi lại

Btw, người ta có thể nói điều này từ thực tế out Tref Tđược hiển thị giống hệt nhau trong các ngôn ngữ CLI khác như VB.Net hoặc C ++ / CLI.
ach

@AndrewPiliser: đúng. Giả sử rằng mã sẽ biên dịch theo bất kỳ cách nào (bạn không cố gắng thực hiện quy định khi bạn không nên), IL sẽ giống hệt nhau.
jmoreno

4

đây là một bài viết thú vị về chủ đề có thể trả lời câu hỏi của bạn:

http://www.dotnetperls.com/ref

điểm ưa thích:

"Sự khác biệt giữa ref và out không nằm trong Runtime Ngôn ngữ chung, mà là ở chính ngôn ngữ C #."

cập nhật:

nhà phát triển cấp cao trong công việc của tôi vừa chứng thực câu trả lời của @ jmoreno, vì vậy hãy chắc chắn rằng bạn đã đọc nó!.


Vì vậy, nếu tôi hiểu chính xác, không có sự khác biệt ở cấp độ IL, điều đó ngụ ý rằng họ không thể có hành vi thời gian chạy khác nhau. Điều này sẽ mâu thuẫn với những gì MSDN nói. Tuy nhiên, bài viết thú vị!
Gábor Angyal

@ GáborAngyal bạn không tình cờ có một liên kết đến bài viết MSDN phải không? Thật tuyệt khi có điều đó ở đây nếu ý kiến ​​khác nhau
Dan Beaulieu

Ở đây bạn đi: msdn.microsoft.com/en-gb/l Library / t3c3bfhx.aspx , nhưng đó là trong câu hỏi của tôi suốt :)
Gábor Angyal

1
Những gì stringphải làm với tất cả điều này?
Robert Harvey

Nó chỉ là một cách diễn đạt từ bài báo. Đã cập nhật để xóa dòng thứ hai ..
Dan Beaulieu

2

Thời gian chạy ? Hoàn toàn không có. Bạn không thể quá tải một phương thức có cùng tham số chỉ khác nhau bởi từ khóa ref hoặc out.

Hãy thử biên dịch cái này và bạn sẽ gặp lỗi biên dịch "Phương thức có cùng chữ ký đã được khai báo":

    private class MyClass
    {
        private void DoSomething(out int param)
        {
        }
        private void DoSomething(ref int param)
        {
        }
    }

Để trả lời câu hỏi này: "... tại sao có hai công cụ rất giống nhau trong C # cho các trường hợp sử dụng quá hẹp?"

Từ khả năng đọc mã và quan điểm API, có một sự khác biệt rất lớn. Là người tiêu dùng API, tôi biết rằng khi "out" được sử dụng, API không phụ thuộc vào tham số out. Là nhà phát triển API, tôi thích "ra" và chỉ sử dụng "ref" khi thực sự cần thiết (RARELY!). Xem tài liệu tham khảo này cho một cuộc thảo luận tuyệt vời:

/programming/1516876/when-to-use-ref-vs-out

Thông tin hỗ trợ: Tôi đã biên dịch phương pháp sau và phân tách nó. Tôi đã sử dụng các từ khóa ref và out (trong ví dụ này), nhưng mã lắp ráp không thay đổi ngoại trừ tham chiếu địa chỉ như tôi mong đợi:

    private class MyClass
    {
        internal void DoSomething(out int param)
        {
            param = 0;
        }
    }

00000000 push ebp
00000001 mov ebp, esp
00000003 push edi
00000004 đẩy esi
00000005 đẩy ebx
00000006 sub esp, 34h
00.000.009 xor eax, eax
0000000b mov dword ptr [ebp-10h], eax
0000000e mov dword ptr [ebp-1ch], EAX
00000011 mov dword ptr [ebp-3Ch], ecx
00.000.014 mov dword ptr [ebp-40h], edx
00.000.017 cmp dword ptr ds: [008B1710h], 0
0000001e je 00.000.025
00.000.020 gọi 6E6B601E
00.000.025 nop
param = 0;
00000026 Mov eax, dword ptr [ebp-40h]
00000029 xor edx, edx
0000002b Mov dword ptr [eax], edx
}
0000002d nop
0000002e lea Esp, [ebp-0Ch]
00000031 pop ebx
00000032 pop esi
00000033 pop edi
00000034 pop ebp
00000035 ret

Tôi đang đọc lắp ráp chính xác?


Những gì bạn viết là chính xác, nhưng xin lưu ý rằng đó không phải là một hàm ý rõ ràng rằng không có sự khác biệt về thời gian chạy vì sự quá tải này không được phép.
Gábor Angyal

Ahh - điểm tốt! Bất cứ ai có thể tháo rời các mã ở trên và chứng minh tôi đúng hay sai? Tôi rất tệ khi đọc lắp ráp, nhưng tò mò muốn biết.
Shmoken

Được rồi - Tôi đã phân tách mã bằng cách sử dụng "out" và "ref" và tôi không thể thấy bất kỳ sự khác biệt nào đối với phương thức
DoS Something
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.