240. DynamicXmlObject

שימוש נחמד נוסף בDynamicObject הוא יצירת Accessor נוח יותר לעבודה מול Xmlים.

איך זה עובד:

נירש מDynamicObject. אנחנו בעצם נעטוף Xml:

1
2
3
4
5
6
7
8
9
public class DynamicXmlObject : DynamicObject
{
private readonly XElement mElement;
public DynamicXmlObject(XElement element)
{
mElement = element;
}
}

כעת את הפונקציה TryGetMember נממש ע"י גישה לXml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
string propertyName = binder.Name;
XAttribute attribute = mElement.Attribute(propertyName);
if (attribute != null)
{
result = attribute.Value;
return true;
}
XElement element = mElement.Element(propertyName);
if (element != null)
{
if (!element.HasElements)
{
result = element.Value;
}
else
{
result = new DynamicXmlObject(element);
}
return true;
}
return base.TryGetMember(binder, out result);
}

כעת אם יש לנו Xml נוכל לגשת לProperties שלו בצורה נוחה יותר:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
XElement myXml =
new XElement("Person",
new XElement("Name", "Yossi"),
new XElement("Age", 31),
new XElement("LastName", "Levi"),
new XElement("Address",
new XAttribute("City", "Tel Aviv"),
new XElement("Street", "Namir Road")));
dynamic person = new DynamicXmlObject(myXml);
string age = person.Age; // 31
string lastName = person.LastName; // Levi
dynamic address = person.Address;
string city = address.City; // Tel Aviv

יש פה חסרון כי המתודות של XElement וXAttribute מחזירות stringים ולכן תמיד נקבל stringים.. לא מצאתי דרך לפתור את זה. (אם מישהו מוצא, אני אשמח לשמוע)

נוכל לעשות אותו הדבר גם להשמה של Properties:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public override bool TrySetMember(SetMemberBinder binder, object value)
{
string propertyName = binder.Name;
if (!(value is DynamicXmlObject))
{
mElement.SetElementValue(propertyName, value);
return true;
}
else
{
XElement element =
((DynamicXmlObject) value).mElement;
element.Name = propertyName;
mElement.Add(element);
return true;
}
return base.TrySetMember(binder, value);
}

ואז בעצם נוכל לכתוב את מה שכתבנו קודם כך:

1
2
3
4
5
6
7
person.Age = 31;
person.FirstName = "Yossi";
person.LastName = "Levi";
dynamic address = new DynamicXmlObject(newXElement("Address"));
address.City = "Tel Aviv";
address.Street = "Namir Road";
person.Address = address;

שיוצר את הXml האלגנטי:

1
2
3
4
5
6
7
8
9
<Person>
<Age>31</Age>
<FirstName>Yossi</FirstName>
<LastName>Levi</LastName>
<Address>
<City>Tel Aviv</City>
<Street>Namir Road</Street>
</Address>
</Person>

כעקרון זוהי הדגמה של מה אפשר לעשות עםDynamicObject.

זה לא בהכרח הBest Practice, וקיימים כבר פתרונות מאוד טובים לבעיה של הפיכת Xml לאובייקט, ביניהם Xsd וכו’.

אבל זה מגניב, ויכול להתאים למספר מקומות…

סופ"ש דינאמי טוב!

שתף