Các thuộc tính có thể được thêm động trong C # không?


143

Có thể thêm thuộc tính khi chạy hoặc thay đổi giá trị của thuộc tính khi chạy không?

Câu trả lời:


67

Các thuộc tính là siêu dữ liệu tĩnh. Các tập hợp, mô-đun, loại, thành viên, tham số và giá trị trả về không phải là đối tượng hạng nhất trong C # (ví dụ: System.Typelớp chỉ là một đại diện được phản ánh của một loại). Bạn có thể lấy một thể hiện của một thuộc tính cho một loại và thay đổi các thuộc tính nếu chúng có thể ghi được nhưng điều đó sẽ không ảnh hưởng đến thuộc tính vì nó được áp dụng cho loại đó.


68

Điều này thực sự phụ thuộc vào chính xác những gì bạn đang cố gắng thực hiện.

Công cụ System.ComponentModel.TypeDescriptor có thể được sử dụng để thêm thuộc tính cho các loại, thuộc tính và thể hiện đối tượng và nó cũng có giới hạn là bạn phải sử dụng nó để truy xuất các thuộc tính đó. Nếu bạn đang viết mã tiêu thụ các thuộc tính đó và bạn có thể sống trong những giới hạn đó, thì tôi chắc chắn sẽ đề xuất nó.

Theo như tôi biết, điều khiển PropertyGrid và bề mặt thiết kế phòng thu trực quan là những thứ duy nhất trong BCL tiêu thụ các công cụ TypeDescriptor. Trên thực tế, đó là cách họ làm khoảng một nửa những việc họ thực sự cần làm.


7
Trên thực tế, hầu hết các sử dụng ràng buộc dữ liệu TypeDescriptor- không chỉ PropertyGrid.
Marc Gravell

1
Bất kỳ cách giải quyết nào để thêm các thuộc tính siêu dữ liệu thuộc tính trong dự án Silverlight (ở đâu TypeDescriptorTypeDescriptionProviderkhông được triển khai?
Shimmy Weitzhandler

1
Điều quan trọng cần lưu ý, TypeDescriptor.GetAttribut () không xử lý các thuộc tính trùng lặp. Nó chỉ chọn cuối cùng của loại thuộc tính. Ex [Attr(1), Attr(2), Attr(3)]chỉ Attr(3)được tìm thấy.
ohmusama

11

Bạn không thể. Một cách giải quyết khác có thể là tạo ra một lớp dẫn xuất trong thời gian chạy và thêm thuộc tính, mặc dù điều này có thể là một chút quá mức.


10

Chà, để khác biệt, tôi đã tìm thấy một bài viết tham khảo bằng Reflection.Emit để làm như vậy.

Đây là liên kết: http://www.codeproject.com/KB/cs/dotnetattribut.aspx , bạn cũng sẽ muốn xem xét một số ý kiến ​​ở cuối bài viết, bởi vì các phương pháp có thể được thảo luận.


10
Lưu ý rằng bạn có thể tạo các thuộc tính trong thời gian chạy với các lớp Reflection.Emit, NHƯNG bạn có thể liên kết chúng với các lớp bạn đã xây dựng với gói Emit chứ không phải với các lớp hiện có.
Panos

thật là một câu trả lời vô ích =)) tất cả chúng ta quan tâm đến các lớp hiện có ở đây, không phải các lớp động.
Vô vọng

@ Không cần thiết, bạn có thể phân lớp YourClassthành YourRuntimeClassWithAttributes.
Mote

@Motes không chắc ý của bạn là gì, các lớp của tôi đều được xác định trước, điều đó có nghĩa là tất cả các lớp cơ sở (mà các lớp của tôi kế thừa) cũng nên được xác định / xác định trước. Tôi không thể nghĩ ra bất kỳ cách nào để nó liên quan đến thứ gì đó được tạo ra một cách linh hoạt bằng Reflection.Emit.
Vô vọng

1
@ Không cần thiết, nếu bạn muốn thêm các thuộc tính động vào một lớp hiện có YourClass, bạn có thể phân lớp nó trong thời gian chạy và tạo một lớp giống hệt với một tên hơi khác cũng có các thuộc tính được tạo động mong muốn và đa hình sẽ cho phép mã kiểm tra kiểu vẫn nhận dạng cơ sở của bạn.
Bỏ phiếu

4

Không, không phải vậy.

Các thuộc tính là siêu dữ liệu và được lưu trữ ở dạng nhị phân trong tập hợp đã biên dịch (đó cũng là lý do tại sao bạn chỉ có thể sử dụng các loại đơn giản trong chúng).


3

Tôi không tin như vậy. Ngay cả khi tôi sai, điều tốt nhất bạn có thể hy vọng là thêm chúng vào toàn bộ Loại, không bao giờ là phiên bản của Loại.


22
TypeDescriptor.AddAttribut (Object, Attribution []) thêm các thuộc tính cấp lớp vào thể hiện thành phần đích.
Peter Wone

3

Nếu bạn cần một cái gì đó để có thể thêm động, các thuộc tính c # không phải là cách. Nhìn vào việc lưu trữ dữ liệu trong xml. Gần đây tôi đã thực hiện một dự án mà tôi đã bắt đầu w / các thuộc tính, nhưng cuối cùng đã chuyển sang tuần tự hóa w / xml.


1
có thể đó không phải là một cách hay nhưng đó là cách mà nhiều thư viện khác chọn sử dụng và để tùy chỉnh hành vi của các thư viện đó, chúng tôi có một yêu cầu để chơi với sự phản chiếu =)) thực sự là một sự bế tắc.
Vô vọng

3

Tại sao bạn cần phải? Các thuộc tính cung cấp thêm thông tin để phản ánh, nhưng nếu bên ngoài bạn biết thuộc tính nào bạn muốn thì bạn không cần chúng.

Bạn có thể lưu trữ dữ liệu meta bên ngoài tương đối dễ dàng trong cơ sở dữ liệu hoặc tệp tài nguyên.


1
Loại bỏ nồi hơi. Sẽ không hữu ích nếu bạn có thể có một lớp tự động tạo các thuộc tính dựa trên mã trong lớp? Tôi đang cố gắng tìm ra một cái gì đó như thế này để giảm nồi hơi trong các đối tượng SQL CLR. Sẽ dễ dàng trong các ngôn ngữ khác ... xem paulgraham.com/avg.html
Duncan Bayne

1

Tôi đã rất cố gắng với System.ComponentModel.TypeDescriptor mà không thành công. Điều đó không có nghĩa là nó không hoạt động nhưng tôi muốn xem mã cho điều đó.

Trong phần đối ứng, tôi muốn thay đổi một số giá trị Thuộc tính. Tôi đã làm 2 chức năng hoạt động tốt cho mục đích đó.

        // ************************************************************************
        public static void SetObjectPropertyDescription(this Type typeOfObject, string propertyName,  string description)
        {
            PropertyDescriptor pd = TypeDescriptor.GetProperties(typeOfObject)[propertyName];
            var att = pd.Attributes[typeof(DescriptionAttribute)] as DescriptionAttribute;
            if (att != null)
            {
                var fieldDescription = att.GetType().GetField("description", BindingFlags.NonPublic | BindingFlags.Instance);
                if (fieldDescription != null)
                {
                    fieldDescription.SetValue(att, description);
                }
            }
        }

        // ************************************************************************
        public static void SetPropertyAttributReadOnly(this Type typeOfObject, string propertyName, bool isReadOnly)
        {
            PropertyDescriptor pd = TypeDescriptor.GetProperties(typeOfObject)[propertyName];
            var att = pd.Attributes[typeof(ReadOnlyAttribute)] as ReadOnlyAttribute;
            if (att != null)
            {
                var fieldDescription = att.GetType().GetField("isReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
                if (fieldDescription != null)
                {
                    fieldDescription.SetValue(att, isReadOnly);
                }
            }
        }

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.