เพิ่มคุณสมบัติ C # แบบไดนามิกที่รันไทม์


89

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

ฉันใช้ไลบรารีที่ทำงานผ่านการไตร่ตรองเพื่อทำสิ่งที่ชาญฉลาดมากมายกับวัตถุที่มีคุณสมบัติ สิ่งนี้ใช้ได้กับคลาสที่กำหนดไว้เช่นเดียวกับคลาสไดนามิก ฉันต้องก้าวไปอีกขั้นและทำบางอย่างตามบรรทัดต่อไปนี้:

public static object GetDynamicObject(Dictionary<string,object> properties) {
    var myObject = new object();
    foreach (var property in properties) {
        //This next line obviously doesn't work... 
        myObject.AddProperty(property.Key,property.Value);
    }
    return myObject;
}

public void Main() {
    var properties = new Dictionary<string,object>();
    properties.Add("Property1",aCustomClassInstance);
    properties.Add("Property2","TestString2");

    var myObject = GetDynamicObject(properties);

    //Then use them like this (or rather the plug in uses them through reflection)
    var customClass = myObject.Property1;
    var myString = myObject.Property2;

}

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

คำตอบ:


105

คุณเคยดู ExpandoObject หรือไม่?

ดู: http://blogs.msdn.com/b/csharpfaq/archive/2009/10/01/dynamic-in-c-4-0-introducing-the-expandoobject.aspx

จาก MSDN:

คลาส ExpandoObject ช่วยให้คุณสามารถเพิ่มและลบสมาชิกของอินสแตนซ์ในขณะรันและยังตั้งค่าและรับค่าของสมาชิกเหล่านี้ คลาสนี้รองรับการเชื่อมโยงแบบไดนามิกซึ่งช่วยให้คุณสามารถใช้ไวยากรณ์มาตรฐานเช่น sampleObject.sampleMember แทนไวยากรณ์ที่ซับซ้อนมากขึ้นเช่น sampleObject.GetAttribute ("sampleMember")

ให้คุณทำสิ่งดีๆเช่น:

dynamic dynObject = new ExpandoObject();
dynObject.SomeDynamicProperty = "Hello!";
dynObject.SomeDynamicAction = (msg) =>
    {
        Console.WriteLine(msg);
    };

dynObject.SomeDynamicAction(dynObject.SomeDynamicProperty);

จากรหัสจริงของคุณคุณอาจสนใจมากกว่า:

public static dynamic GetDynamicObject(Dictionary<string, object> properties)
{
    return new MyDynObject(properties);
}

public sealed class MyDynObject : DynamicObject
{
    private readonly Dictionary<string, object> _properties;

    public MyDynObject(Dictionary<string, object> properties)
    {
        _properties = properties;
    }

    public override IEnumerable<string> GetDynamicMemberNames()
    {
        return _properties.Keys;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (_properties.ContainsKey(binder.Name))
        {
            result = _properties[binder.Name];
            return true;
        }
        else
        {
            result = null;
            return false;
        }
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        if (_properties.ContainsKey(binder.Name))
        {
            _properties[binder.Name] = value;
            return true;
        }
        else
        {
            return false;
        }
    }
}

ด้วยวิธีนี้คุณเพียงแค่ต้องการ:

var dyn = GetDynamicObject(new Dictionary<string, object>()
    {
        {"prop1", 12},
    });

Console.WriteLine(dyn.prop1);
dyn.prop1 = 150;

การได้มาจาก DynamicObject ช่วยให้คุณสามารถกำหนดกลยุทธ์ของคุณเองในการจัดการคำขอสมาชิกแบบไดนามิกเหล่านี้โปรดระวังว่ามีสัตว์ประหลาดอยู่ที่นี่:คอมไพเลอร์จะไม่สามารถตรวจสอบการโทรแบบไดนามิกของคุณได้มากนักและคุณจะไม่ได้รับ Intellisense ที่อยู่ในใจ


40

ขอบคุณ @Clint สำหรับคำตอบที่ยอดเยี่ยม:

แค่อยากจะเน้นว่ามันง่ายแค่ไหนในการแก้ปัญหานี้โดยใช้ Expando Object:

    var dynamicObject = new ExpandoObject() as IDictionary<string, Object>;
    foreach (var property in properties) {
        dynamicObject.Add(property.Key,property.Value);
    }

4

คุณสามารถ deserialize สตริง json ของคุณลงในพจนานุกรมจากนั้นเพิ่มคุณสมบัติใหม่จากนั้นทำให้เป็นอนุกรม

 var jsonString = @"{}";

        var jsonDoc = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonString);

        jsonDoc.Add("Name", "Khurshid Ali");

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