2010-03-02 19 views
41

Một số ưu điểm/nhược điểm khi sử dụng thư viện Reflection.Emit so với CodeDOM để tạo mã động khi chạy là gì?Reflection.Emit vs CodeDOM

Tôi đang cố gắng tạo một số lớp động (tương đối phức tạp) trong một hệ thống dựa trên siêu dữ liệu có sẵn khi chạy ở dạng XML. Tôi sẽ tạo các lớp mở rộng các lớp hiện có trong hội đồng ứng dụng, triển khai các giao diện bổ sung, thêm các phương thức và ghi đè các thành viên ảo và trừu tượng.

Tôi muốn đảm bảo rằng tôi chọn kỹ thuật thích hợp trước khi tôi đi sâu vào quá trình triển khai. Bất kỳ thông tin nào về cách các kỹ thuật tạo mã khác nhau này sẽ khác nhau sẽ hữu ích. Ngoài ra, bất kỳ thông tin nào về các thư viện nguồn mở đơn giản hóa hoặc sắp xếp hợp lý với API làm việc cũng sẽ hữu ích.

+1

Khi đọc điều này, NHibernate là điều đầu tiên xuất hiện trong đầu tôi. Nó có đáng để xem chúng hoạt động như thế nào? – quip

+1

Tôi đang thực sự xem xét điều đó. Họ sử dụng Reflection.Emit, nhưng không rõ tại sao họ lại chọn điều đó so với CodeDOM. – LBushkin

Trả lời

50

Tôi nghĩ rằng những điểm mấu chốt về CodeDOM và Reflection.Emit đang theo dõi:

  • CodeDOM tạo ra mã nguồn C# và thường được sử dụng khi tạo mã để được bao gồm như là một phần của một giải pháp và biên soạn trong IDE (ví dụ, các lớp LINQ to SQL, WSDL, XSD đều hoạt động theo cách này). Trong trường hợp này, bạn cũng có thể sử dụng các lớp từng phần để tùy chỉnh mã được tạo. Nó kém hiệu quả hơn, vì nó tạo ra nguồn C# và sau đó chạy trình biên dịch để phân tích nó (một lần nữa!) Và biên dịch nó. Bạn có thể tạo mã bằng cách sử dụng các cấu trúc mức tương đối cao (tương tự như các câu lệnh C# expression #) chẳng hạn như các vòng lặp.

  • Reflection.Emit tạo IL để tạo trực tiếp một hội đồng cũng chỉ được lưu trữ trong bộ nhớ. Kết quả là hiệu quả hơn rất nhiều. Bạn phải tạo mã IL cấp thấp (các giá trị được lưu trữ trên stack; vòng lặp phải được thực hiện bằng cách sử dụng các bước nhảy), do đó tạo ra bất kỳ logic phức tạp hơn nào cũng khó khăn một chút.

Nói chung, tôi nghĩ Reflection.Emit thường được coi là cách ưu tiên để tạo mã khi chạy, trong khi CodeDOM được ưu tiên khi tạo mã trước khi biên dịch. Trong kịch bản của bạn, cả hai đều có thể làm việc tốt (mặc dù CodeDOM có thể cần các đặc quyền cao hơn, vì nó thực sự cần gọi trình biên dịch C#, là một phần của bất kỳ cài đặt .NET nào).

Một tùy chọn khác sẽ là sử dụng Expression class. Trong .NET 4.0 nó cho phép bạn tạo mã tương đương với các biểu thức và câu lệnh C#. Tuy nhiên, nó không cho phép bạn tạo ra một lớp. Vì vậy, bạn có thể kết hợp điều này với Reflection.Emit (để tạo ra các lớp ủy quyền thực hiện cho mã được tạo ra bằng cách sử dụng Expression). Đối với một số trường hợp, bạn cũng có thể không cần phân cấp đầy đủ - thường là từ điển của các đại biểu được tạo động như Dictionary<string, Action> có thể đủ tốt (nhưng tất nhiên, nó phụ thuộc vào kịch bản chính xác của bạn).

+0

Tôi hiểu rằng CodeDOM cũng có thể [tạo mã trong bộ nhớ] (http://msdn.microsoft.com/en-us/library/system.codedom.compiler.compilerparameters.generateinmemory.aspx)? –

+0

Bạn có thể giải thích cách bạn có thể sử dụng các lớp học một phần bằng CodeDom không? Nếu nghiên cứu của tôi cho thấy bất cứ điều gì, đó là bạn không thể sử dụng 'partial' ở tất cả: nó thậm chí không phải là một tùy chọn trong' TypeAttributes' enum. –

+0

Câu trả lời hoàn chỉnh. Cảm ơn bạn. – nawfal

14

Mã nhắm mục tiêu CodeDom có ​​xu hướng dễ bảo trì hơn, vì bạn đang tạo mã C# chứ không phải IL (nhiều người hơn có thể đọc C# hơn IL). Hơn nữa, nếu bạn nhận được mã CodeDom của bạn sai, bạn nhận được một lỗi trình biên dịch; nếu bạn tạo ra IL không hợp lệ, bạn sẽ nhận được một ngoại lệ nghiêm trọng hoặc một sự cố.

Tuy nhiên, vì CodeDom gọi trình biên dịch csc.exe, nên sẽ chậm hơn một chút để lấy mã sẵn sàng để sử dụng. Với Reflection.Emit, bạn có thể tạo mã trực tiếp vào bộ nhớ.

CodeDom có ​​lẽ là tốt cho hầu hết mọi thứ; XmlSerializer và trình thiết kế WinForms sử dụng nó.

+0

XmlSerializer sử dụng CodeDOM để làm gì? Xin lỗi, tôi có thể tra cứu trong Reflector nhưng tôi lười vì sự chú ý của tôi bị phân chia giữa nhiều vấn đề khác và vì bạn đã trả lời, tôi cho rằng bạn đã đầu tư thời gian để bạn có thể gõ câu trả lời mà không tốn quá nhiều thời gian hoặc. –

+0

@ WaterCoolerv2 Nếu tôi phải đoán, họ xây dựng một hội đồng để đọc/ghi các loại mục tiêu. Tôi đã từng được đưa vào một dự án với một lớp truy cập dữ liệu khổng lồ, phản chiếu. Đó là con chó chậm chạp, nên người dùng ghét nó, nhưng không ai biết cách sửa nó. Tôi đã thực hiện nó ngay lập tức với một sự kết hợp của bộ nhớ đệm và Emit. Ngoài việc cắt bỏ Reflection chậm ra khỏi ảnh, bạn cũng có thể loại bỏ overhead bằng cách kiểm tra các loại đầu tiên và phát ra các mã opcode thích hợp trực tiếp vào một phương thức, thay vì phân nhánh hoặc gọi các đại biểu chuyên biệt trong quá trình tuần tự hóa. – Daniel

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