2015-01-17 20 views
9

Tôi biết. Một câu hỏi tương tự đã được hỏi.Nhận tên Phương thức đã ném ngoại lệ

nhưng tôi đã không có những giải pháp chính xác từ đó.

Tôi có sự kiện nhấp nút mà tôi có phương thức FillCombo().

Nút Bấm kiện

private void button1_Click(object sender, EventArgs e) 
{ 
     try 
     { 
      cmbTemplates.Items.Clear(); 
      lstFiles.Clear(); 
      FillCombo();     
     } 
     catch (Exception ex) 
     { 
      MethodBase site = ex.TargetSite; 
      Log(ex.ToString(), site == null ? null : site.Name);     
     } 
} 

Khi tôi sửa lỗi, tôi thấy rằng các ngoại lệ xảy ra từ FillCombo() phương pháp. Sau đó, tôi nhận được giá trị site.NameWinIOError thay vì FillCombo.

Tôi đã thử một phương thức khác GetExecutingMethodName() đã được trả lời bởi Chris Gessler trong câu hỏi How to get the name of the method that caused the exception. Vì vậy, tôi đã cố gắng gửi tên của phương pháp đó gây ra ngoại lệ sử dụng phương pháp GetExecutingMethodName()

Log(ex.ToString(), GetExecutingMethodName()); 

Nhưng tôi có kết quả như System.Windows.Forms.Control.OnClick thay vì FillCombo.

Làm cách nào để có được tên thực tế của phương pháp gây ra ngoại lệ?

+0

breakpoint sử dụng để gỡ lỗi mã của bạn và nhìn vào stacktrace – saurabh64

+1

tôi có thể biết trong chế độ Dubug. Nhưng tôi cần phải đăng nhập các lỗi vào một tập tin. Trong môi trường sản xuất, những người sẽ ngồi và Debug !!! @ saurabh64 –

+1

Bạn nên ghi lại toàn bộ dấu vết ngăn xếp. Điều này thường sẽ cung cấp đủ ngữ cảnh để xác định vấn đề. –

Trả lời

11

.net hỗ trợ nhận thông tin theo dõi ngăn xếp từ một ngoại lệ. Bạn có thể lọc ra phương thức (và tên của nó) bằng cách kiểm tra frame đầu tiên (origin).

new StackTrace(ex).GetFrame(0).GetMethod().Name 

này có lẽ sẽ cung cấp cho bạn một cách chính xác giống như các targetsite (chiến thắng io), nhưng bạn có thể kiểm tra stacktrace cho mã đầu tiên sử dụng, hoặc frame đầu tiên trong loại của bạn, hoặc bất cứ nhu cầu của bạn.

Ví dụ, nhận được tên của thrower thủ phạm trong lắp ráp hiện tại của bạn:

var s = new StackTrace(ex); 
var thisasm = Assembly.GetExecutingAssembly();     
var methodname = s.GetFrames().Select(f => f.GetMethod()).First(m => m.Module.Assembly == thisasm).Name; 
+0

Điều này khác với thuộc tính 'Exception.TargetSite' như thế nào? Và làm thế nào để có được tên của phương thức 'FillCombo()' của OP? –

+0

@PeterDuniho Vui lòng xem chỉnh sửa. Stacktrace ra khỏi ngoại lệ là điểm vào để lọc ra các nhu cầu chính xác. Hơi chậm khi thêm ví dụ do thiếu studio trực quan tại vị trí hiện tại của tôi và đang tìm kiếm dotnetfiddle;) –

+0

Làm việc hoàn hảo. Tôi đã thử mã. Tôi thậm chí có thể nhận được tên của sự kiện trong trường hợp ngoại lệ xảy ra trước khi thực hiện phương thức FillCombo.Cảm ơn rất nhiều :) @ Me.Name –

6

Điều quan trọng là phải hiểu ý nghĩa của "phương pháp đã ném ngoại lệ". Khi một ngoại lệ xảy ra, có một phương pháp cụ thể thực sự thực thi. Chỉ vì tại một số điểm trước khi ngoại lệ, bạn đã gọi phương thức FillCombo() của riêng mình, điều đó không có nghĩa đó là phương pháp đã ném ngoại lệ. Tuy nhiên,

Tuy nhiên, phương pháp FillCombo() sẽ nằm trong ngăn xếp ngăn xếp. Đó là lý do tại sao nó rất hữu ích để đăng nhập toàn bộ dấu vết stack. Thật vậy, tôi thường chỉ ghi lại toàn bộ đối tượng Exception (ví dụ: ex.ToString() hoặc chỉ chuyển đối tượng ngoại lệ sang string.Format() hoặc tương tự, sẽ gọi ToString() cho bạn). Điều này sẽ bao gồm loại ngoại lệ, thông báo, toàn bộ dấu vết ngăn xếp và thậm chí cả thông tin ngoại lệ bên trong nếu có.


Mã bạn nhận được từ câu hỏi khác, cho phương thức GetExecutingMethodName(), không thực sự là IMHO hữu ích. Bạn sẽ lưu ý rằng điều thực sự là thu thập thông tin theo dấu vết ngăn xếp của vị trí thực thi hiện tại, tìm phương pháp đầu tiên được khai báo trong một loại khác với loại được tuyên bố là GetExecutingMethodName().

Đây là sai cho mục đích của bạn vì hai lý do:

  1. Có vẻ bạn đã tuyên bố rằng phương pháp trong cùng một lớp nơi Click xử lý sự kiện của bạn được công bố. Điều này có nghĩa là phương thức xử lý sự kiện bị bỏ qua và vì vậy bạn có được người gọi phương thức đó, là phương thức Control.OnClick() (tức là phương thức thực sự tăng sự kiện).

Thành thật mà nói, tôi thấy câu trả lời cụ thể là lẻ, vì .NET đã cung cấp API để truy xuất MethodInfo của phương pháp hiện đang thực hiện: MethodBase.GetCurrentMethod. Và đây là cách đáng tin cậy hơn so với mã Chris Gessler đã viết.

  1. Có vấn đề hơn, bạn không có cơ hội gọi phương thức này tại thời điểm ngoại lệ được ném! Tốt nhất (tức là ngay cả khi bạn đối phó với câu hỏi về nơi mà phương thức trợ giúp được khai báo), tất cả những gì gọi là sẽ cho bạn biết rằng bạn đang ở phương thức button1_Click() của bạn. Nhưng bạn đã biết điều đó, bởi vì mã bạn đang viết để xử lý ngoại lệ là trong phương thức đó.


Nếu bạn muốn biết tên của phương pháp trong phương pháp hiện thực của bạn mà được gọi trước khi ngoại lệ xảy ra, bạn có thể kết hợp hai kỹ thuật: lấy tên của phương pháp hiện đang thực hiện, và sau đó vượt qua với một phương thức lấy cả chuỗi đó và chuỗi dấu vết ngăn xếp từ đối tượng Exception và để phương thức đó phân tích cú pháp chuỗi dấu vết ngăn xếp để tìm khung ngay trước phương pháp hiện đang thực thi trong theo dõi.

Đó là một chút đau, nhưng có thể thực hiện được. Dưới đây là một ví dụ về những gì mà sẽ trông như thế (đơn giản proof-of-concept chương trình giao diện điều khiển):

static void Main(string[] args) 
{ 
    try 
    { 
     CallForException(); 
    } 
    catch (Exception e) 
    { 
     Console.WriteLine("Exception occurred calling {0} method", GetCallForExceptionThisMethod(MethodBase.GetCurrentMethod(), e)); 
    } 
} 

private static string GetCallForExceptionThisMethod(MethodBase methodBase, Exception e) 
{ 
    StackTrace trace = new StackTrace(e); 
    StackFrame previousFrame = null; 

    foreach (StackFrame frame in trace.GetFrames()) 
    { 
     if (frame.GetMethod() == methodBase) 
     { 
      break; 
     } 

     previousFrame = frame; 
    } 

    return previousFrame != null ? previousFrame.GetMethod().Name : null; 
} 

private static void CallForException() 
{ 
    DoActualException(); 
} 

private static void DoActualException() 
{ 
    throw new NotImplementedException(); 
} 

Cuối cùng, hãy nhớ rằng do phương pháp nội tuyến và tối ưu hóa khác, thậm chí là một vết đống đầy đủ có thể có một số bất thường trong đó, kể cả thậm chí không có tên thật của phương thức mà ngoại lệ được ném ra. Đó là một lý do khác để ghi lại toàn bộ đối tượng Exception thường hữu ích hơn nhiều; càng có nhiều bối cảnh, bạn càng có khả năng tái tạo lại những gì đã xảy ra.

+0

Rất thông tin. Cũng giải thích về xử lý ngoại lệ - PROS và CONS. +1. Cảm ơn bạn :) –

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