2012-01-18 32 views
27

Nói rằng tôi có đoạn mã sau: "fjuk"Out thông số và các ngoại lệ

static void Fjuk(out string str) 
    { 
     str = "fjuk!"; 
     throw new Exception(); 
    } 

    static void Main(string[] args) 
    { 
     string s = null; 
     try 
     { 
      Fjuk(out s); 
     } 
     catch (Exception) 
     { 
      Console.WriteLine(s ?? ""); 
     } 
    } 

Khi tôi kiểm tra nó, s đã được khởi tạo khi được sử dụng trong khối catch.
Điều này có được đảm bảo bởi đặc điểm kỹ thuật hay phụ thuộc vào việc triển khai không? (Tôi đã tìm kiếm spec C# 3 nhưng không thể tìm ra bản thân mình)

+0

Tôi không biết về đặc điểm kỹ thuật, nhưng nó chắc chắn là những gì tôi mong đợi. Tôi hy vọng rằng việc khởi tạo các biến thành viên, các thuộc tính vv cũng sẽ vẫn có sẵn trong khối catch của bạn. –

+1

Trường hợp của Eric Lippert khi bạn cần anh ta ... :) –

+0

@jb. Có gì sai với [MSDN] (http://msdn.microsoft.com/en-us/library/t3c3bfhx (v = vs.80) .aspx)? – gdoron

Trả lời

23

Khá nhiều, đó là một khía cạnh của những gì out phương tiện; trước tiên, lưu ý rằng out không thực sự tồn tại - chúng tôi chỉ thực sự cần phải xem xét ref (out chỉ là ref với một số "chuyển nhượng xác định" chỉnh tại trình biên dịch). ref có nghĩa là "chuyển địa chỉ này" - nếu chúng tôi thay đổi giá trị thông qua địa chỉ, thì hiển thị ngay lập tức - sau cùng, cập nhật bộ nhớ trên ngăn xếp Main. Nó không thể trừu tượng điều này (để trì hoãn ghi) vì giá trị có thể là, ví dụ, một số cấu trúc quá khổ đang sử dụng ref đặc biệt cho mục đích tránh sao chép nó trên ngăn xếp (một cách tiếp cận được sử dụng rộng rãi trong XNA vv).

5

Nó "bảo lãnh"out tham số thay đổi giá trị với memory address của tham số.

Từ khóa ngoài khiến đối số được chuyển qua tham chiếu. Điều này tương tự như từ khóa ref, ngoại trừ ref đó yêu cầu biến được khởi tạo trước khi được thông qua.

từ MSDN

4

Nếu phương pháp ném ngoại lệ, thông số đầu ra không được đảm bảo được đặt. Nếu phương thức thoát mà không có ngoại lệ, thông số đầu ra được đảm bảo được thiết lập.

Trong trường hợp của bạn, phương thức sẽ luôn đặt tham số đầu ra, nhưng trình biên dịch không phân tích mã của phương thức theo cách đó. Nếu phương thức thoát với một ngoại lệ, tham số đầu ra vẫn không được coi là chắc chắn được đặt.

Mã của bạn trong trình xử lý ngoại lệ không dựa vào biến được đặt bởi lệnh gọi phương thức, vì bạn đang đặt biến khi được tạo. Nếu bạn không đặt biến khi nó được tạo ra, xử lý ngoại lệ không thể sử dụng nó, bởi vì nó không được bảo đảm đến được thiết lập:

string s; 
try { 
    Fjuk(out s); 
    Console.WriteLine(s); // here the variable is guaranteed to be set 
} catch (Exception) { 
    Console.WriteLine(s); // here it's not, so this won't compile 
} 
+0

Có, tôi đã xem xét rõ ràng là nó không kiểm tra mã trong phương thức được gọi, nhưng không làm rõ điều đó trong ví dụ của tôi. Cảm ơn bạn đã chỉ ra điều này! – Niklas

1

Nó được bảo đảm từ quan điểm của Fjuk nhưng không phải của Main.

Trong Fjuk ngoại lệ được ném sau khi thông số được đặt. Trong khi có thể được sắp xếp lại được thực hiện bởi trình biên dịch, jitter và CPU, sẽ không có đơn đặt hàng lại sao cho thứ tự quan sát được bằng một thay đổi luồng đơn lẻ. Vì một chuỗi đơn có thể "chú ý" nếu tham số không được đặt trước khi ngoại lệ được ném, tham số được đảm bảo được đặt.

Trong Main mặc dù, chúng tôi không có kiến ​​thức về chi tiết thực hiện Fjuk, vì vậy khi trình biên dịch phân tích Main, nó không thể phụ thuộc vào điều đó.Do đó trong sự thay đổi mà chúng ta không gán giá trị cho s trước khi cuộc gọi:

static void Main() 
{ 
    string s; 
    try 
    { 
     Fjuk(out s); 
     Console.WriteLine(s ?? "");//fine 
    } 
    catch (Exception) 
    { 
     Console.WriteLine(s ?? "");//compiler error 
    } 
    Console.WriteLine(s ?? "");//compiler error 
} 

Nỗ lực đầu tiên sử dụng s ngay sau khi cuộc gọi đến Fjuk là tốt, vì mỗi người chỉ có thể đạt được điều đó nếu Fjuk thành công, và nếu Fjuk thành công thì s phải được chỉ định. Tuy nhiên, trong trường hợp thứ hai và thứ ba, có thể đến các đường thẳng đó mà không cần Fjuk thành công và vì không thể phân tích được Main cho dù ngoại lệ có thể được ném trước khi s được đặt hay không, việc sử dụng s phải bị cấm.

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