สามารถเพิ่มคุณสมบัติแบบไดนามิกใน C # ได้หรือไม่?


คำตอบ:


67

แอตทริบิวต์เป็นข้อมูลเมตาแบบคงที่ แอสเซมบลีโมดูลชนิดสมาชิกพารามิเตอร์และค่าส่งคืนไม่ใช่วัตถุชั้นหนึ่งใน C # (เช่นSystem.Typeคลาสเป็นเพียงการแสดงชนิดของการสะท้อน) คุณสามารถรับอินสแตนซ์ของแอททริบิวต์สำหรับประเภทและเปลี่ยนคุณสมบัติได้หากพวกเขาสามารถเขียนได้ แต่จะไม่ส่งผลกระทบต่อแอททริบิวที่ใช้กับประเภทนั้น


68

สิ่งนี้ขึ้นอยู่กับสิ่งที่คุณพยายามจะทำให้สำเร็จ

System.ComponentModel.TypeDescriptorสิ่งที่สามารถนำมาใช้เพื่อเพิ่มแอตทริบิวต์ประเภทคุณสมบัติและกรณีวัตถุและมันก็มีข้อ จำกัด ที่คุณต้องใช้มันเพื่อดึงคุณสมบัติเหล่านั้นเช่นกัน หากคุณกำลังเขียนโค้ดที่ใช้คุณสมบัติเหล่านั้นและคุณสามารถใช้งานได้ภายในข้อ จำกัด เหล่านั้นฉันขอแนะนำอย่างแน่นอน

เท่าที่ฉันรู้ตัวควบคุม PropertyGrid และพื้นผิวการออกแบบสตูดิโอภาพเป็นสิ่งเดียวใน BCL ที่ใช้สิ่งที่ TypeDescriptor ในความเป็นจริงนั้นเป็นวิธีที่พวกเขาทำประมาณครึ่งสิ่งที่พวกเขาต้องทำจริงๆ


7
ที่จริงแล้วการผูกข้อมูลส่วนใหญ่ใช้TypeDescriptor- PropertyGridไม่เพียง แต่
Marc Gravell

1
วิธีแก้ปัญหาใด ๆ เพื่อเพิ่มคุณสมบัติข้อมูลเมตาคุณสมบัติในโครงการ Silverlight (ที่TypeDescriptorและTypeDescriptionProviderไม่ได้ใช้งานหรือไม่)
Shimmy Weitzhandler

1
สิ่งสำคัญที่ควรทราบ TypeDescriptor.GetAttributes () ไม่ได้จัดการแอตทริบิวต์ที่ซ้ำกัน จะเลือกเฉพาะประเภทแอตทริบิวต์สุดท้ายเท่านั้น พบ[Attr(1), Attr(2), Attr(3)]เฉพาะอดีต Attr(3)
ohmusama

11

คุณทำไม่ได้ วิธีแก้ปัญหาหนึ่งอาจเป็นการสร้างคลาสที่ได้รับเมื่อรันไทม์และเพิ่มแอ็ตทริบิวต์แม้ว่านี่อาจเป็น overkill เล็กน้อย


10

ก็แตกต่างกันฉันพบบทความที่อ้างอิงโดยใช้ Reflection. ทำเช่นนั้น

นี่คือลิงค์: http://www.codeproject.com/KB/cs/dotnetattributes.aspxคุณจะต้องการดูความคิดเห็นบางส่วนที่ด้านล่างของบทความเนื่องจากมีการพูดถึงแนวทางที่เป็นไปได้


10
โปรดทราบว่าคุณสามารถสร้างแอททริบิวตอนรันไทม์ด้วยคลาส Reflection.Emit แต่คุณสามารถผูกคลาสเหล่านั้นกับคลาสที่คุณสร้างด้วยแพ็คเกจ Emit และไม่ใช่คลาสที่มีอยู่
Panos

สิ่งที่เป็นคำตอบที่ไร้ประโยชน์ =)) เราทุกคนสนใจเกี่ยวกับชั้นเรียนที่มีอยู่ที่นี่ไม่ใช่แบบไดนามิก
สิ้นหวัง

@Hopeless คุณอาจประเภทรองลงไปYourClass YourRuntimeClassWithAttributes
Motes

@Motes ไม่แน่ใจว่าคุณหมายถึงอะไรคลาสของฉันถูกกำหนดไว้ล่วงหน้านั่นหมายความว่าคลาสพื้นฐานทั้งหมด (ที่คลาสของฉันสืบทอด) ควรถูกกำหนด / กำหนดไว้ล่วงหน้าด้วย ฉันไม่คิดว่าจะมีส่วนเกี่ยวข้องกับสิ่งที่สร้างขึ้นแบบไดนามิกโดยใช้ Reflection.Emit
สิ้นหวัง

1
@Hopeless หากคุณต้องการเพิ่มคุณสมบัติแบบไดนามิกไปยังคลาสที่มีอยู่YourClassคุณสามารถคลาสย่อยที่ runtime และสร้างคลาสที่เหมือนกันด้วยชื่อที่แตกต่างกันเล็กน้อยที่มีคุณสมบัติที่สร้างขึ้นแบบไดนามิกที่ต้องการและ polymorphism จะอนุญาตให้พิมพ์รหัสการตรวจสอบ baseclass ของคุณ
Motes

4

ไม่มันไม่ใช่.

แอตทริบิวต์เป็น meta-data และเก็บไว้ในรูปแบบไบนารีในแอสเซมบลีที่คอมไพล์ (นั่นเป็นเหตุผลว่าทำไมคุณสามารถใช้ประเภทแบบง่าย ๆ เท่านั้น)


3

ฉันไม่เชื่ออย่างนั้น แม้ว่าฉันผิดที่ดีที่สุดที่คุณสามารถหวังจะเพิ่มพวกเขาไปยังประเภททั้งไม่เคยอินสแตนซ์ของพิมพ์


22
TypeDescriptor.AddAttributes (Object, Attribute []) เพิ่มแอตทริบิวต์ระดับระดับให้กับอินสแตนซ์องค์ประกอบเป้าหมาย
Peter Wone

3

หากคุณต้องการสิ่งที่จะสามารถเพิ่มแบบไดนามิกคุณสมบัติ c # ไม่ใช่วิธี ดูที่การจัดเก็บข้อมูลใน xml ฉันเพิ่งทำโครงการที่ฉันเริ่ม w / คุณลักษณะ แต่ในที่สุดก็ย้ายไปเป็นอนุกรม w / xml


1
อาจไม่ใช่วิธีที่สวยงาม แต่เป็นวิธีที่ห้องสมุดอื่น ๆ เลือกที่จะใช้และเพื่อปรับแต่งพฤติกรรมของห้องสมุดเหล่านั้นเรามีข้อกำหนดที่จะเล่นกับไตร่ตรอง =)) การหยุดชะงักจริงๆ
สิ้นหวัง

3

ทำไมคุณต้อง แอ็ตทริบิวต์ให้ข้อมูลเพิ่มเติมสำหรับการสะท้อน แต่ถ้าคุณรู้จากภายนอกว่าต้องการคุณสมบัติใด

คุณสามารถเก็บข้อมูลเมตาจากภายนอกได้อย่างง่ายดายในฐานข้อมูลหรือไฟล์ทรัพยากร


1
การกำจัดหม้อไอน้ำ มันจะมีประโยชน์ไหมถ้าคุณมีคลาสที่สร้างแอททริบิวต์โดยอัตโนมัติตามโค้ดภายในคลาส? ฉันพยายามที่จะคิดออกเช่นนี้เพื่อลดสำเร็จรูปในวัตถุ SQL CLR จะเป็นเรื่องง่ายในภาษาอื่น ๆ ... ดูpaulgraham.com/avg.html
Duncan Bayne

1

ฉันพยายามอย่างหนักกับ System.ComponentModel.TypeDescriptor ไม่สำเร็จ ไม่ได้หมายความว่ามันใช้งานไม่ได้ แต่ฉันอยากเห็นโค้ดสำหรับเรื่องนั้น

ในส่วนที่เคาน์เตอร์ฉันต้องการเปลี่ยนค่าแอตทริบิวต์บางอย่าง ฉันทำหน้าที่ 2 อย่างที่ทำงานได้ดีสำหรับจุดประสงค์นั้น

        // ************************************************************************
        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);
                }
            }
        }

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.