2009-09-23 32 views
34

Làm cách nào tôi có thể đặt thuộc tính InnerException của đối tượng Exception, trong khi tôi đang ở trong hàm tạo của đối tượng đó? Điều này sẽ tóm tắt để tìm và thiết lập trường sao lưu của một thuộc tính không có setter.Đặt InnerException của .NET Ngoại lệ đối tượng

btw: Tôi đã thấy điều này (http://evain.net/blog/articles/2009/05/01/getting-the-field-backing-a-property-using-reflection) nhưng tìm kiếm giải pháp không dựa trên IL, nếu có thể.

Các constructor ngoại lệ là nơi mà các loại ngoại lệ được tạo ra, vì vậy tôi không thể gọi nó bằng cách sử dụng MyException constructor lớp cơ sở(): base (...) vv

+0

Theo dõi lại; sau đó (như tôi đã đề cập) làm kiểu tạo trong một phương thức tĩnh * phía trước * của ctor, thay vì bên trong phần thân của hàm tạo. –

+1

Làm cho ý nghĩa hơn để đóng gói trong trường hợp của tôi. –

+0

... nhưng tôi lấy ý kiến ​​của bạn, tôi sẽ xem xét việc biến nhà máy thành một nhà máy để tránh chi phí phản ánh. –

Trả lời

12

Tại sao bạn không thể gọi hàm khởi tạo lấy InnerException làm tham số? Nếu vì một lý do nào đó không thể, trường sao lưu trong System.Exception là:

private Exception _innerException; 

Tôi đã tìm thấy nó bằng cách sử dụng Redgate's Reflector. Sử dụng sự phản chiếu tôi cho rằng bạn có thể thiết lập ngoại lệ bên trong.

Chỉnh sửa: Trong hầu hết các trường hợp, không nên truy cập trường riêng tư qua phản ánh, nhưng tôi không biết đủ về trường hợp của NT để biết chắc đó là một ý tưởng hay hay.

+9

Tôi không thể nghĩ ra một ví dụ hợp lý mà phản xạ là cách đúng đắn để thực hiện điều này ... –

+0

Điều này có ý nghĩa đối với các kịch bản động liên quan đến việc kích hoạt ngoại lệ mà không thể biết trước được ngoại lệ bên trong. . –

+3

Không, không. Nó thực sự không; nó phá vỡ đóng gói. Sử dụng một phương thức tĩnh trong chuỗi ': base (SomeMethod (...), ...)'. –

7
Exception exceptionWithMoreInfo = new Exception("extra info", ex); 

sẽ được thực hành bình thường giả sử bạn đã mắc kẹt một ngoại lệ mà bạn muốn thêm nhiều thông tin hơn trước khi sủi bọt.

+1

không giúp bạn trong ctor ngoại lệ, mặc dù. – Joey

59

Bạn đặt ngoại lệ bên trong bằng cách gọi ctor cơ sở:

public MyException(string message, Exception innerException) 
     : base(message, innerException) {...} 

Nếu bạn cần phải chạy một số mã để có được ngoại lệ, sử dụng một phương pháp tĩnh:

public MyException(SomeData data) : base(GetMessage(data), GetInner(data)) {...} 
static Exception GetInner(SomeData data) {...} // <===== your type creation here! 
static string GetMessage(SomeData data) {...} 
1

Không phải là InnerException phải được thiết lập khi sử dụng các nhà xây dựng Exception(string, Exception)? Tôi nghĩ đó là do thiết kế mà bạn không thể thay đổi điều này bằng cách khác nhưng bạn luôn có thể trì hoãn để các nhà xây dựng thích hợp vào thời điểm xây dựng:

class MyException : Exception { 
    public MyException() 
     : base("foo", new Exception("bar")) 
    { 
     ... 
    } 

    ... 
} 

Tôi nghĩ bạn không nên bao giờ phá vỡ chuỗi ngoại lệ trong mã của bạn vì đó thường dẫn đến lỗi bạn sẽ không bao giờ tìm thấy nữa.

29

Lớp Exception có một nhà xây dựng quá tải chấp nhận ngoại lệ bên trong như một tham số:

Exception exc = new Exception("message", new Exception("inner message")); 

Đây có phải là những gì bạn đang tìm kiếm?

+0

Trong khi điều này không trả lời câu hỏi của mình trực tiếp, nó trả lời những gì hầu hết mọi người tìm kiếm này đang tìm kiếm. – rolls

1

Nếu tôi hiểu câu hỏi của bạn, bạn muốn làm một cái gì đó như thế này:

Exception ex = new Exception("test"); 
Exception innerEx = new Exception("inner"); 
ex.GetType().GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(ex, innerEx); 

Nếu bạn đang ở trong các nhà xây dựng của một đối tượng được thừa kế từ Exception bạn sẽ sử dụng this thay vì ex đầu tiên.

Nhưng điều này có thể không phải là cách tốt nhất để xử lý bất cứ điều gì bạn đang cố xử lý.

+0

Có gì sai với ngoại lệ innerEx = ngoại lệ mới ("bên trong"); Ngoại lệ ex = new Exception ("test", innerEx); ? –

+0

Ông đang cố gắng sửa đổi đối tượng cũ mà không được tạo ra trong ngữ cảnh, tôi tạo ra nó chỉ cho mục đích demo. Trên thực tế trong trường hợp của mình, ông đang cố gắng sửa đổi trường hợp này. – pauloya

+0

+1: Điều này trả lời câu hỏi khá ngớ ngẩn của tôi về cách buộc ngoại lệ bên trong của ngoại lệ là chính nó, do đó gây ra những điều thú vị như phương thức ToString() kích hoạt tràn ngăn xếp. – Brian

1

Sử dụng Trình phản xạ của Redgate để tìm trường. Tôi nghi ngờ việc thực hiện ngoại lệ sẽ thay đổi ... Nhưng đó là một rủi ro!

+0

Tại sao bạn lại nghi ngờ điều này? Bạn có cơ sở nào để thực hiện đánh giá này? Nếu tôi là Microsoft, tôi sẽ thay đổi việc thực hiện chỉ để kích thích những kẻ ngu ngốc phụ thuộc vào chi tiết thực hiện nội bộ của các lớp người khác. –

+2

Dựa trên số lượng chi tiết như vậy đã thay đổi trong các bản cập nhật khung trước đây? –

+1

@ John: Điều tốt bạn không làm việc cho MS sau đó! – Scooterville

0

Tôi biết tôi thực sự đến muộn với bữa tiệc, nhưng tôi thấy điều này có hiệu quả.

public class MyException: Exception 
{ 
    public void SetInnerException(Exception exception) 
    { 
     typeof(Exception) 
      .GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance) 
      .SetValue(this, exception); 
    } 
} 

Bí quyết là để có được lĩnh vực này thực tế Exception loại của _innerException, và sau đó thiết lập giá trị ngoại lệ bên trong để dụ lớp học của bạn (MyException trong trường hợp này).

Điều này cũng hoạt động đối với các biến.

Exception mainException = new Exception(); 
typeof(Exception) 
    .GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance) 
    .SetValue(mainException , new Exception("Something bad happened!")); 
Các vấn đề liên quan