DCSIMG
C# 4.0 Part 6 - DynamicObject class and IDynamicMetaObjectProvider interface - שלמה גולדברג (הרב דוטנט)

שלמה גולדברג (הרב דוטנט)

מרצה בסלע ויועץ בעולם ה - net.

C# 4.0 Part 6 - DynamicObject class and IDynamicMetaObjectProvider interface

 

אחד הדברים המתסכלים בללמוד חומר על טכנולוגיה חדשה שעדיין לא יצאה בגרסה סופית, זה שבכל גרסת ניסיון נוספת ה - API עלול להשתנות, וזה מתסכל כי אף אחד לא מעדכן אותך שה - API שהיה קיים בגרסה אחת השתנה והוא נראה שונה לגמרי בגרסה הנוכחית, ב - PDC הודגם ממשק שנקרא IDynamicObject - הממשק הזה נעלם, לא קיים יותר. ולמעשה היות שכל הפוסטים שלי בנושא אינם מדברים על הגרסה הסופית של המוצר, יכול מאוד להיות שכש - C# 4.0  תצא לאויר בגרסה רשמית הדברים שוב ישתנו. אז קחו את זה לתשומת לבכם.
 
 
 
כמו שהבטחתי בפוסט הקודם אני אראה בפוסט הנוכחי איך אפשר לשנות את ההתנהגות של dynamic object.
 
 
 
הדבר היחיד שאתם צריכים לעשות זה לרשת מ - class שנקרא DynamicObject
 
לדוגמא, אם אנחנו רוצים לכתוב אובייקט שמתנהג כמו Dictionary, רק שהגישה ל - keys תהיה גישה למאפיינים ולא דרך indexer, אפשר לכתוב את הקוד הבא:
 
 

    public class DynamicDictionary : DynamicObject

    {

        private Dictionary<string, object> dic = new Dictionary<string, object>();

 

        public override bool TrySetMember(SetMemberBinder binder, object value)

        {

            if (!dic.ContainsKey(binder.Name))

            {

                dic.Add(binder.Name, value);

            }

            else

            {

                dic[binder.Name] = value;

            }

 

            return true;

        }

 

        public override bool TryGetMember(GetMemberBinder binder, out object result)

        {

            if (!dic.ContainsKey(binder.Name))

            {

                return base.TryGetMember(binder, out result);

            }

 

            result = dic[binder.Name];

            return true;

        }

    }

 
והשימוש בו יראה כך:
 

    dynamic d = new DynamicDictionary();

    d.Name = "shlomo";

    d.Age = 24;

 

    Console.WriteLine(d.Name);

    Console.WriteLine(d.Age);

 
 
ולמעשה יצרנו אובייקט (קסום) שכאילו יוצר מאפיינים בלי שבאמת הם קיימים - כשהשמות של המאפיינים הם בפועל המפתחות ב - dictionary.
 
 
דוגמא נוספת, יותר שימושית היא - גישה לאלמנטים של xml באמצעות מאפיין ולא באמצעות indexer, פוסט ששווה לקרוא בנושא, כאן. (הדוגמא הבאה דומה לדוגמא בפוסט)
 
שימו לב לקוד:
 

    class DynamicXmlElement : DynamicObject

    {

        public XmlElement Element { get; private set; }

 

        public DynamicXmlElement(XmlElement element)

        {

            Element = element;

        }

 

        public override bool TryGetMember(GetMemberBinder binder, out object result)

        {

            List<XmlElement> elements = new List<XmlElement>();

            foreach (XmlElement item in Element)

            {

                if (item.Name == binder.Name)

                {

                    elements.Add(item);

                }

            }

 

            if (elements.Count == 0)

            {

                return base.TryGetMember(binder, out result);

            }

 

            if (elements.Count == 1)

            {

                result = new DynamicXmlElement(elements[0]);

                return true;

            }

 

 

            result = elements.ConvertAll<DynamicXmlElement>(e => new DynamicXmlElement(e));

            return true;

        }

 

        public override string ToString()

        {

            return Element.InnerText;

        }

    }

 
 
נעבור על הקוד:
 
ה - class יורש מ - DynamicObject ב - Ctor  הוא מקבל אובייקט מסוג XmlElement שהוא עובד איתו.
 
המתודה העיקרית TryGetMember מקבלת שני פרמטרים: הראשון - זה ה - binder שמכיל מידע אודות הבקשה והשני הוא result שאמור להחזיר את התשובה.
 
אני רץ על כל האלמנטים ב - Element בודק האם יש בתוכו אלמנטים עם השם שנשלח,
 
במידה ולא מצאתי שום אלמנט אני פונה ל - base שבסופו של דבר יחזיר Expression של זריקת שגיאה.
 
במידה ומצאתי רק אחד - אני מחזיר מופע חדש של DynamicXmlElement כשאני שולח את האלמנט שמצאתי ל - Ctor.
 
במידה ומצאתי יותר מאחד, אני מחזיר List של DynamicXmlElement.
 
 
נניח שה - Xml נראה כך:
 

<Persons>

  <Person>

    <Name>shlomo</Name>

    <Age>24</Age>

    <Childern>

      <Child>

        <Name>yossi</Name>

        <Age>6</Age>

      </Child>

      <Child>

        <Name>meir</Name>

        <Age>4</Age>

      </Child>

    </Childern>

  </Person>

  <Person>

    <Name>noam</Name>

    <Age>24</Age>

    <Childern>

      <Child>

        <Name>david</Name>

        <Age>3</Age>

      </Child>

      <Child>

        <Name>mika</Name>

        <Age>3</Age>

      </Child>

    </Childern>

  </Person>

</Persons>

 
 
נניח שיש לי מאפיין שנקרא SampleXml שמחזיר אותו, הקוד ב - Main יראה כך:
 

    XmlDocument doc = new XmlDocument();

    doc.LoadXml(SampleXml);

 

    dynamic dxe = new DynamicXmlElement(doc["Persons"]);

    dynamic persons = dxe.Person;

 

    foreach (dynamic item in persons)

    {

        Console.WriteLine(item.Name);

        Console.WriteLine(item.Age);

 

        foreach (dynamic child in item.Childern.Child)

        {

            Console.WriteLine(child.Name);

            Console.WriteLine(child.Age);

        }

    }

 
שימו לב שהגישה לכל האלמנטים של ה - xml היא דרך מאפיינים ולא דרך indexer או מתודות. שזה נראה הרבה יותר נחמד.
 
 
במידה ואתם לא רוצים לרשת מ - DynamicObject כי זה חוסם לכם את אפשרות הירושה ממישהו אחר אפשר לממש את IDynamicMetaObjectProvider
 
 

    public interface IDynamicMetaObjectProvider

    {

        DynamicMetaObject GetMetaObject(Expression parameter);

    }

 
והקוד שלכם נראה כך:
 

    class DynamicXmlDocument : XmlDocument, IDynamicMetaObjectProvider

    {

        #region IDynamicMetaObjectProvider Members

 

        public DynamicMetaObject GetMetaObject(Expression parameter)

        {

            return new XmlDocumentMetaObject(parameter, this);

        }

 

        class XmlDocumentMetaObject : DynamicMetaObject

        {

            public XmlDocumentMetaObject(Expression parameter, object value)

                : base(parameter, BindingRestrictions.Empty, value)

            {

 

            }

        }

        #endregion

    }

 
אבל אז צריך לעשות override למתודות של DynamicMetaObject וזה באמת נושא לפוסט נפרד.
פורסם: Jun 23 2009, 08:31 AM by Shlomo | with 1 comment(s) |
תגים:, , , ,

תוכן התגובה

טל כתב/ה:

נחמד מאוד!

# July 7, 2009 10:59 AM
שלח תגובה

(שדה חובה)  

(שדה חובה)  

(אופציונלי)

(שדה חובה) 

Please add 2 and 6 and type the answer here:


Enter the numbers above: