2009-03-14 30 views

Trả lời

24

Bạn không thể thay đổi định nghĩa lớp khi chạy. Tuy nhiên, bạn có thể tạo một lớp mới kế thừa từ lớp gốc (nếu nó không phải là sealed) và khai báo trường đó. Bạn có thể làm điều này bằng cách phát ra mã IL thích hợp bằng cách sử dụng System.Reflection.Emit.

6

Không, C# không cho phép monkey-patching.

Bạn có thể tạo các lớp mới sử dụng CodeDOM hoặc Reflection.Emit, nhưng bạn không thể sửa đổi các lớp hiện có.

+1

Nó được gọi là khỉ vá? Từ đó bắt nguồn từ đâu? –

+0

Không biết nó xuất phát từ đâu, nhưng tôi đã thêm một liên kết đến mục nhập Wikipedia. –

+1

Khỉ vá là một thuật ngữ đến từ Ruby. Jeff Atwood đã viết về nó trong một bài đăng blog một vài năm trước đây. –

1

Không chính xác.

Tuy nhiên, bạn có thể triển khai ICustomTypeDescriptor để ước tính nó, và sau đó chỉ cần sử dụng một hashtable để lưu trữ cặp tên/giá trị. Rất nhiều khuôn khổ trong đó sử dụng phản ánh yêu cầu ICustomTypeDescriptor đầu tiên.

+0

Cảm ơn, tôi đã thử phương pháp này, nhưng nó không hoạt động đối với tôi. Tôi đang cố gắng để impelment giao diện IExpando để cho phép javascript mã gọi các lĩnh vực không tồn tại trong lớp C# của tôi. Ví dụ: var o = ActiveXObject mới ('mCom'); o.ArbitraryField = "Foo"; Xin lưu ý rằng ArbitraryField không tồn tại ở lớp của tôi. –

+0

Bạn vừa thử triển khai IReflect chưa? Đó là cách để thực hiện IDispatch/IExpando cho interop với các ngôn ngữ động (ít nhất là trước khi C# 4.0). http://msdn.microsoft.com/en-us/library/system.reflection.ireflect.aspx Tôi đã thực hiện điều này chính xác với một triển khai có thể bắt đầu và nó hoạt động tốt – codekaizen

1

Không cho đến khi C# 4.0 bổ sung tra cứu động và dựa trên CLR 4.0 kết hợp DLR, sau đó nó sẽ không được thêm vào lớp, vì lớp sẽ không có trong hình.

+0

Tôi sẽ không nghĩ rằng điều này sẽ có thể trong C# 4.0. Tôi nghĩ rằng bạn sẽ không thể thay đổi các loại hiện có. Tuy nhiên, tôi có thể tưởng tượng rằng bạn có thể tạo một số đối tượng động (ví dụ: đến từ Ruby) và thay đổi nó. –

+0

Đó là những gì tôi có nghĩa là "không nghiêm chỉnh được thêm vào một lớp học, như các lớp học sẽ không có trong hình". Thay vào đó, các đối tượng riêng lẻ được tham chiếu bởi 'động' sẽ có thể chấp nhận gán cho thuộc tính không tồn tại trước đó và xử lý việc này bằng cách thêm động một thuộc tính. –

6

C# không cho phép điều đó vì tất cả các lớp của nó đều dựa trên Siêu dữ liệu. CLR (không phải C#) không cho phép thêm trường vào siêu dữ liệu khi chạy (1). Đây là cách duy nhất để C# có thể thêm một trường tại runitme.

Điều này không giống như các ngôn ngữ động như IronPython mà về cơ bản không có lớp siêu dữ liệu cụ thể. Chúng có nhiều cấu trúc động hơn có thể được thay đổi khi chạy. Tôi tin rằng IronPython chỉ đơn giản là giữ cho các thành viên của nó (các trường và các phương thức) với số tiền mà một hashtable có thể dễ dàng bị thay đổi khi chạy.

Trong C# 3.0, tài nguyên tốt nhất của bạn là sử dụng Reflection.Emit. Nhưng điều này sẽ tạo ra một lớp hoàn toàn mới so với việc thay đổi một lớp hiện có.

(1) Có một số API nhất định chẳng hạn như API lược tả hoặc ENC cho phép điều này nhưng tôi không chắc liệu capabalities của họ có mở rộng để thêm trường hay không.

1

như những người khác đã nói, điều này là không thể. Lý do cho câu hỏi của bạn là gì? Nếu bạn cần lưu trữ một số dữ liệu bổ sung trong lớp tự động, sau đó bạn có thể có thể chỉ cần sử dụng từ điển:

class My { 
    Dictionary<string, object> data; 
    public My() { data = new Dictionary<string, object>(); } 
} 

.. nhưng nó thực sự phụ thuộc vào những gì bạn thực sự muốn đạt được?

+0

Mục tiêu của tôi là triển khai giao diện IExpando. Mục tiêu siêu của tôi là cho phép mã javascript thêm các trường vào đối tượng ActiveX động và theo "cách javascript". Ví dụ: var myobj = new ActiveXObject ('server.object'); myobj.ArbitraryField = "một cái gì đó"; Xin lưu ý rằng taht ArbirtaryField không tồn tại –

1

Xem this question để biết cách thực hiện đơn giản trong C# 4.0, bằng cách đúc ExpandoObject làm IDictionary, làm cho giá trị được thêm vào từ điển trở thành thuộc tính của đối tượng. Tôi chứng minh điều này trong another answer of mine cho thấy rằng họ thực sự trở thành tài sản.

Tuy nhiên, điều này chỉ có thể xảy ra với phiên bản ExpandoObject hoặc theo phân lớp DynamicObject.

Cũng có thể sử dụng với các lớp khác nếu chúng triển khai IDynamicMetaObjectProvider, nhưng tôi nghĩ có quá nhiều công việc liên quan để làm cho nó hoạt động bình thường.

0

Có lẽ bạn có thể sử dụng mẫu Decorator.

Trong lập trình hướng đối tượng, mẫu trang trí là mẫu thiết kế cho phép hành vi được thêm vào một đối tượng riêng lẻ, tĩnh hoặc động, mà không ảnh hưởng đến hành vi của các đối tượng khác từ cùng một lớp.

http://www.dofactory.com/Patterns/PatternDecorator.aspx

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