2012-03-01 20 views
7

Tôi đã bắt đầu sử dụng các lớp triển khai IDisposable để viết các khối trong luồng, với câu lệnh sử dụng. Điều này rất hữu ích để giữ cho lồng ghép chính xác và tránh các bộ phận bắt đầu/kết thúc bị thiếu hoặc bị đặt sai.sử dụng (IDisposable obj = new ...) trong C# để viết các khối mã trong luồng (ví dụ: XML)

Về cơ bản, hàm tạo ghi khởi đầu của một khối (ví dụ: mở thẻ XML), Vứt bỏ() kết thúc (ví dụ: đóng thẻ XML). Ví dụ là UsableXmlElement dưới đây (nó dành cho các XML lớn, vì vậy LINQ to XML hoặc XmlDocument trong bộ nhớ không có tùy chọn).

Tuy nhiên, IDisposable này không triển khai mẫu phức tạp do Microsoft đề xuất, với Trình phá hủy/Trình kết thúc, phương thức Vứt bỏ (bool) riêng biệt và GC.SuppressFinalize(). Vứt bỏ chỉ đơn giản là viết các yếu tố kết thúc, và đó là nó.

Có bất kỳ khía cạnh nào dưới đây hay đây là cách tốt để duy trì việc lồng ghép đúng các yếu tố?

class UsableXmlElement : IDisposable 
{ 
    private XmlWriter _xwriter; 

    public UsableXmlElement(string name, XmlWriter xmlWriter) 
    { 
     _xwriter = xmlWriter; 
     _xwriter.WriteStartElement(name); 
    } 

    public void WriteAttribute<T>(string name, T value) 
    { 
     _xwriter.WriteStartAttribute(name); 
     _xwriter.WriteValue(value); 
     _xwriter.WriteEndAttribute(); 
    } 

    public void WriteValue<T>(T value) 
    { 
     _xwriter.WriteValue(value); 
    } 

    public void Dispose() 
    { 
     _xwriter.WriteEndElement(); 
    } 
} 

Cách sử dụng như sau:

var xWriter = new XmlWriter(...) 

using(var rootElement = new UsableXmlElement("RootElement", xWriter) 
{ 
    rootElement.WriteAttribute("DocVersion", 123) 
    using(var innerElement = new UsableXmlElement("InnerElement", xwriter) 
    { 
     // write anything inside Inner element 
    } 
} 

Hệ quả là:

<RootElement DocVersion="123"> 
    <InnerElement> 
     <!-- anything --> 
    </InnerElement> 
</RootElement> 
+2

Tại sao nó lại là một vấn đề? Bạn không có bất kỳ tài nguyên không được quản lý trong UsableXmlElement của bạn, vì vậy bạn không cần bất kỳ finalizers, tôi nghĩ rằng ... – user1096188

+0

Oh, và bạn không cần WriteValue và WriteAttribute là chung chung. Nó không làm bất cứ điều gì, như _xwriter.WriteValue sẽ luôn được gọi với một tham số đối tượng. – user1096188

+0

Hummmmmm ........ – code4life

Trả lời

2

Có xuống bên này,

số Destructors (finalizers) nên tránh anyw ay, ngay cả một lớp học với các nguồn lực thường có thể làm (tốt hơn) mà không có.

hoặc đây có phải là cách hay để duy trì việc lồng ghép các yếu tố chính xác không?

Có. Bạn có thể sử dụng System.Web.Mvc.Html.MvcForm làm tham chiếu.

những IDisposable không thực hiện các mô hình phức tạp khuyến cáo của Microsoft

Đó 'đầy đủ' mô hình là đúng nhưng ngày. Nó chỉ mô tả tình hình cho một nguồn tài nguyên không được quản lý 'trần'. Một tài liệu tham khảo chính thức để xử lý các tài nguyên được quản lý chỉ không được cung cấp, không may mắn thay.

3

Nhược điểm chính mà tôi thấy (ngoài việc sử dụng không đúng tiêu chuẩn của tuyên bố sử dụng được cho là vi phạm "nguyên tắc ít ngạc nhiên nhất") là nó sẽ cố gắng liên tục viết tất cả các thẻ kết thúc lồng nhau trong trường hợp ngoại lệ được ném bởi XmlWriter của bạn. Trong lý thuyết ít nhất, bạn có thể có một ngoại lệ ném trong khi viết một thẻ kết thúc bên trong, theo sau là viết thành công của thẻ kết thúc bên ngoài trong các khối "cuối cùng" được tạo ra bởi các báo cáo sử dụng. Điều này sẽ dẫn đến đầu ra không hợp lệ.

+0

Không bao giờ nghe nói nó được gọi là "nguyên tắc ít ngạc nhiên nhất". Tôi sẽ sử dụng biểu thức đó trong tương lai :) –

1

Mẫu phức tạp được sử dụng bởi microsoft được tạo để đảm bảo rằng các tài nguyên không được quản lý được giải phóng, ngay cả khi bạn không gọi Dispose().

Bạn không sử dụng bất kỳ tài nguyên không được quản lý nào trong lớp học của mình. Bạn chỉ cần tận dụng lợi thế của từ khóa using của C# để làm cho mã của bạn dễ đọc hơn và dễ bảo trì hơn. Tôi nghĩ rằng đó là một cách tiếp cận tốt đẹp và tôi cũng đã sử dụng nó trong quá khứ.

Tôi nghĩ rằng nó thậm chí sẽ không có ý nghĩa để sử dụng cấu trúc finalizer, vì bạn cần phải chắc chắn rằng thẻ kết thúc được viết ở vị trí chính xác. Bạn không bao giờ biết khi nào finalizer được gọi, vì vậy bạn không thể chắc chắn khi thẻ kết thúc sẽ được viết nếu bạn quên Vứt bỏ phần tử của bạn. Tài liệu Xml của bạn sẽ vẫn bị rối tung, cho dù thẻ kết thúc không được viết hoàn toàn hay sai vị trí.

Trong trường hợp xấu nhất, khi trình kết thúc cuộc gọi Dispose(), XmlWriter có thể đã được xử lý và bạn nhận được Ngoại lệ. Vì vậy, tốt hơn không có finalizer.

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