ฉันจะสะท้อนถึงสมาชิกของวัตถุไดนามิกได้อย่างไร


131

ฉันต้องการพจนานุกรมคุณสมบัติและค่าจากวัตถุที่ประกาศด้วยคีย์เวิร์ดไดนามิกใน. NET 4 หรือไม่ ดูเหมือนว่าการใช้การสะท้อนกลับจะไม่ได้ผล

ตัวอย่าง:

dynamic s = new ExpandoObject();
s.Path = "/Home";
s.Name = "Home";

// How do I enumerate the Path and Name properties and get their values?
IDictionary<string, object> propertyValues = ???

คำตอบ:


32

หาก IDynamicMetaObjectProvider สามารถระบุชื่อสมาชิกแบบไดนามิกคุณจะได้รับ ดูGetMemberNamesการดำเนินงานใน Apache ได้รับใบอนุญาตบมจห้องสมุดDynamitey (ซึ่งสามารถพบได้ใน nuget) มันทำงานให้ExpandoObjectและDynamicObjects ที่ใช้GetDynamicMemberNamesและอื่น ๆIDynamicMetaObjectProviderที่ให้วัตถุ meta ที่มีการดำเนินการโดยการทดสอบที่กำหนดเองเกินGetDynamicMemberNamesis IDynamicMetaObjectProvider

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


17
ขอบคุณที่ไปถึงจุดที่รหัสคือ var tTarget = target เป็น IDynamicMetaObjectProvider; ถ้า (tTarget! = null) {tList.AddRange (tTarget.GetMetaObject (Expression.Constant (tTarget)). GetDynamicMemberNames ()); }
Flatliner DOA

ขอบคุณสำหรับห้องสมุดที่ยอดเยี่ยมของคุณ ฉันมีปัญหาในการปัดเศษวัตถุแบบไดนามิกไปยังไลบรารีdynamicjson.codeplex.comและสามารถขยายด้วยไลบรารีของคุณได้
JJS

1
กรุณายกตัวอย่าง
Demodave

105

ในกรณีของ ExpandoObject คลาส ExpandoObject จะใช้IDictionary<string, object>คุณสมบัติของมันดังนั้นการแก้ปัญหาจึงไม่สำคัญพอ ๆ กับการหล่อ:

IDictionary<string, object> propertyValues = (IDictionary<string, object>)s;

โปรดทราบว่าสิ่งนี้จะใช้ไม่ได้กับวัตถุไดนามิกทั่วไป ในกรณีเหล่านี้คุณจะต้องเลื่อนลงไปที่ DLR ผ่าน IDynamicMetaObjectProvider


ขอบคุณสำหรับสิ่งนั้นน่าเสียดายที่ตัวอย่างมีขนาดใหญ่เกินไปเล็กน้อย ฉันต้องสามารถตรวจสอบวัตถุแบบไดนามิกโดยที่ไม่รู้ว่ามันเป็นประเภทจริง
Flatliner DOA

2
สิ่งนี้ใช้ได้เฉพาะกับอ็อบเจ็กต์ของคลาส ExpandoObject คลาส DynamicObject เป็นคลาสที่ขยายได้อีกคลาสหนึ่งซึ่งไม่ได้ใช้ IDictionary แต่ใช้ IDynamicMetaObjectProvider
Sharique Abdullah

1
มันตอบคำถามของ OP ว่า
Sharique Abdullah

58

มีหลายสถานการณ์ที่ต้องพิจารณา ก่อนอื่นคุณต้องตรวจสอบประเภทของวัตถุของคุณ คุณสามารถเรียก GetType () สำหรับสิ่งนี้ หากประเภทไม่ใช้ IDynamicMetaObjectProvider คุณสามารถใช้การสะท้อนเช่นเดียวกับวัตถุอื่น ๆ สิ่งที่ต้องการ:

var propertyInfo = test.GetType().GetProperties();

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

หากเป็น DynamicObject (การใช้งาน IDynamicMetaObjectProvider อื่น) คุณต้องใช้วิธีใดก็ตามที่ DynamicObject เปิดเผย DynamicObject ไม่จำเป็นต้อง "เก็บ" รายการคุณสมบัติไว้ที่ใดก็ได้ ตัวอย่างเช่นอาจทำสิ่งนี้ได้ (ฉันใช้ตัวอย่างจากบล็อกโพสต์ของฉันซ้ำ):

public class SampleObject : DynamicObject
{
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = binder.Name;
        return true;
    }
}

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

dynamic obj = new SampleObject();
Console.WriteLine(obj.SampleProperty);
//Prints "SampleProperty".

ดังนั้นคุณไม่มีอะไรจะสะท้อน - วัตถุนี้ไม่มีคุณสมบัติใด ๆ และในขณะเดียวกันชื่อคุณสมบัติที่ถูกต้องทั้งหมดก็จะใช้งานได้

ฉันจะบอกว่าสำหรับการใช้งาน IDynamicMetaObjectProvider คุณต้องกรองการใช้งานที่รู้จักซึ่งคุณสามารถรับรายการคุณสมบัติเช่น ExpandoObject และละเว้น (หรือโยนข้อยกเว้น) สำหรับส่วนที่เหลือ


7
สำหรับฉันแล้วดูเหมือนว่าถ้าประเภทที่ฉันใช้เป็นแบบไดนามิกฉันไม่ควรตั้งสมมติฐานเกี่ยวกับประเภทพื้นฐาน ฉันควรจะโทรหา GetDynamicMemberNames เพื่อรับรายชื่อสมาชิกได้ ดูเหมือนโง่ที่ประเภทคงที่รองรับการตรวจสอบรันไทม์ได้ดีกว่าแบบไดนามิก!
Flatliner DOA

2
คุณสามารถแทนที่เมธอด GetDynamicMemberNames () สำหรับวัตถุไดนามิกเพื่อส่งคืนชื่อรายการของสมาชิกแบบไดนามิก ปัญหาคือไม่รับประกันว่าวัตถุไดนามิกทุกตัวจะมีวิธีนี้ (ExpandoObject ไม่มี) ไม่น่าแปลกใจที่การสะท้อนจะทำงานได้ดีกว่าสำหรับประเภทคงที่ มันถูกสร้างขึ้นสำหรับพวกเขาตั้งแต่แรก ด้วยพลวัตคุณต้องพึ่งพาการทดสอบหน่วยและ TDD มากขึ้น
Alexandra Rusina

1
เอกสาร MSDN สำหรับ GetDynamicMemberNames () กล่าวถึง: "วิธีนี้มีไว้สำหรับจุดประสงค์ในการดีบักเท่านั้น" ไม่ใช่เรื่องน่าสบายใจเลย :(
NicoJuicy

19

ต้องใช้ Newtonsoft Json.Net

ช้าไปหน่อย แต่ฉันมากับสิ่งนี้ มันให้คีย์แก่คุณจากนั้นคุณสามารถใช้สิ่งเหล่านั้นบนไดนามิก:

public List<string> GetPropertyKeysForDynamic(dynamic dynamicToGetPropertiesFor)
{
    JObject attributesAsJObject = dynamicToGetPropertiesFor;
    Dictionary<string, object> values = attributesAsJObject.ToObject<Dictionary<string, object>>();
    List<string> toReturn = new List<string>();
    foreach (string key in values.Keys)
    {
        toReturn.Add(key);                
    }
    return toReturn;
}

จากนั้นคุณก็พูดแบบนี้:

foreach(string propertyName in GetPropertyKeysForDynamic(dynamicToGetPropertiesFor))
{
    dynamic/object/string propertyValue = dynamicToGetPropertiesFor[propertyName];
    // And
    dynamicToGetPropertiesFor[propertyName] = "Your Value"; // Or an object value
}

การเลือกรับค่าเป็นสตริงหรือออบเจ็กต์อื่น ๆ หรือทำแบบไดนามิกอื่นแล้วใช้การค้นหาอีกครั้ง


คุณไม่ต้องการรายชื่อเพื่อส่งคืน
aloisdg ย้ายไปที่ codidact.com

4
ที่สมบูรณ์แบบ! ฉันต้องเปลี่ยนแอตทริบิวต์ JObjectAsJObject = dynamicToGetPropertiesFor; ไปยังแอตทริบิวต์ของ ObjectAsJObject = (JObject) JToken.FromObject (obj); แม้ว่า !!
k25

เพียงเพื่อย้ำสิ่งที่ @ k25 กล่าว คุณต้องแทนที่JObject attributesAsJObject = dynamicToGetPropertiesFor;ด้วยสิ่งที่ต้องการ: var jObject = (JObject) JToken.FromObject(dynamicToGetPropertiesFor);. ณ var objProperties = jObject.ToObject<Dictionary<string, object>>();จุดที่คุณจะได้รับในพจนานุกรมของชื่อคุณสมบัติและคุณค่าด้วยการทำสิ่งที่ชอบ เมื่ออยู่ในมือคุณจะออกไปแข่งขัน สิ่งนี้ไม่จำเป็นต้องมีไดนามิก ใช้งานได้ดีกับทุกสิ่งที่เป็นคลาสย่อยของDynamicObject
Flydog57
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.