2009-06-13 32 views
33

Thuộc tính System.Exception.HResult được bảo vệ. Làm thế nào tôi có thể nhìn trộm bên trong một ngoại lệ và nhận được HResult mà không phải dùng đến sự phản chiếu hoặc các hacks xấu xí khác?Làm cách nào để xác định HResult cho System.IO.IOException?


Đây là tình hình:
Tôi muốn viết một công cụ sao lưu, mở ra và đọc tập tin trên một hệ thống. Tôi mở tệp bằng FileAccess.Read và FileShare.ReadWrite, theo số this guidance, vì tôi không quan tâm liệu tệp đó có mở để viết vào thời điểm tôi đọc hay không.

Trong một số trường hợp, khi một tệp mà tôi đang đọc mở bởi một ứng dụng khác, phương thức System.IO.FileStream.Read() ném một System.IO.IOException, "Quá trình này không thể truy nhập tệp vì một quy trình khác có đã khóa một phần của tệp ". Đây là error 33, hoặc tôi nghĩ HResult 0x80070021. [EDIT: Tôi tin rằng điều này có thể được trả lại khi một quy trình khác gọi LockFileEx để khóa phạm vi byte trong một tệp.]

Tôi muốn tạm dừng và thử lại khi tôi gặp lỗi này. Tôi nghĩ đây là hành động thích hợp để thực hiện ở đây. Nếu quá trình khóa phát hành khóa phạm vi byte một cách nhanh chóng, thì tôi có thể tiếp tục đọc tệp.

Làm cách nào để phân biệt một IOException vì lý do này, với những người khác? Tôi có thể nghĩ theo những cách sau:

  • phản ánh riêng tư - không muốn làm điều đó. Perf sẽ bốc mùi.
  • gọi Exception.ToString() và phân tích cú pháp chuỗi. Cảm thấy hacky. Sẽ không hoạt động trong các phiên bản i18n.

Tôi không thích các tùy chọn này. Không có cách nào tốt hơn, sạch hơn?


Tôi vừa tìm kiếm và tìm thấy System.Runtime.InteropServices.Marshal.GetHRForException. Điều đó sẽ trả về một uint như 0x80070021?

+3

> phản ánh riêng - không muốn làm điều đó. Perf sẽ bốc mùi. - Dù sao thì ngoại lệ stinks cũng vậy, nên tôi sẽ không lo lắng về khía cạnh hoàn hảo. Reflection hiện - tuy nhiên - yêu cầu FullTrust, là xấu xí, và không được hỗ trợ và dễ bị vỡ - đó là lý do tại sao bạn không nên làm điều đó. –

Trả lời

54

Đối với .Net Framework 4.5 trở lên, bạn có thể sử dụng Exception.HResult tài sản:

int hr = ex.HResult; 

Đối với các phiên bản cũ hơn, bạn có thể sử dụng Marshal.GetHRForException để lấy lại HRESULT, nhưng has significant side-effects and is not recommended này:

int hr = Marshal.GetHRForException(ex); 
+0

Cảm ơn rất nhiều! Điều này thực sự dễ dàng phát triển trong trường hợp của C#/COM khả năng tương tác. – rds

+2

+1 Eww, đòi hỏi sự tin tưởng đầy đủ ... Nhưng đó là một giải pháp dù sao. – reSPAWNed

+3

Hãy coi chừng các tác dụng phụ: "Lưu ý rằng phương pháp ** GetHRForException ** đặt ** IErrorInfo ** của chuỗi hiện tại. Điều này có thể gây ra các kết quả không mong muốn cho các phương thức như ** ThrowExceptionForHR ** phương pháp mặc định để sử dụng ** IErrorInfo ** của chuỗi hiện tại nếu nó được thiết lập. " – HugoRune

0

CanRead trợ giúp thuộc tính trong trường hợp này không?
tức là gọi CanRead, nếu trả lại đúng, hãy gọi Read()

+0

Không, CanRead là đúng. Tôi tin rằng 80070021 là một lỗi tạm thời. Nếu tôi đọc tài liệu một cách chính xác, để xử lý nó, thực hành được khuyến nghị là "đợi một lúc và thử lại". – Cheeso

+0

Có thể bạn đã mở tệp để đọc và một người nào khác đã mở tệp đó (sử dụng FileShare.Read), người gọi đầu tiên không thể đọc được nữa không? Đó là những gì bạn có ý nghĩa của thoáng qua? – shahkalpesh

+0

Không, ý tôi là, một quá trình khác được gọi là FileLock hoặc FileLockEx (http://msdn.microsoft.com/en-us/library/aa365203.aspx) trên tệp để khóa một phạm vi trong tệp. Điều này đôi khi được gọi là khóa phạm vi byte. Tại một số điểm, quá trình khóa sẽ giải phóng khóa phạm vi. Đó là ý tôi là "Tạm thời". – Cheeso

0

Bạn đã lược tả một trong các trường hợp này chưa? Tôi tưởng tượng rằng phương pháp phản chiếu không phải là tất cả chậm, đặc biệt là tương đối so với tất cả các công trình khác ứng dụng của bạn sẽ làm và tần suất ngoại lệ này sẽ có khả năng xảy ra.

Nếu hóa ra là một nút cổ chai, bạn có thể xem xét lưu vào bộ nhớ đệm một số thao tác phản chiếu hoặc tạo IL động để truy xuất thuộc tính.

11

Đối với những gì nó có giá trị, System.Exception.HResult không còn được bảo vệ trong .NET 4.5 - chỉ setter được bảo vệ. Điều đó không giúp mã có thể được biên dịch với nhiều phiên bản của khung công tác.

3

Bạn cũng có thể sử dụng giao diện ISerializable:

static class IOExceptionExtensions 
{ 
    public static int GetHResult(this IOException ex) 
    { 
     var info = new SerializationInfo(typeof (IOException), new FormatterConverter()); 
     ex.GetObjectData(info, new StreamingContext()); 
     return info.GetInt32("HResult"); 
    } 
} 
Các vấn đề liên quan