Skip to content

Instantly share code, notes, and snippets.

@melvinstubbe
Created September 25, 2017 20:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save melvinstubbe/477e33d8c026e85a1077eaceaef934a1 to your computer and use it in GitHub Desktop.
Save melvinstubbe/477e33d8c026e85a1077eaceaef934a1 to your computer and use it in GitHub Desktop.
Example of a class that parses an existing XML object into a C# 'dynamic' object
using System;
using System.Dynamic;
using System.Linq;
using System.Xml.Linq;
namespace DynamicExample
{
/// <summary>
/// Parses an existing XML object into a C# 'dynamic' object.
/// </summary>
/// <seealso cref="System.Dynamic.DynamicObject" />
public class DynamicXmlParser : DynamicObject
{
private readonly XElement root;
/// <summary>
/// Initializes a new instance of the <see cref="DynamicXmlParser"/> class.
/// </summary>
/// <param name="root">The root.</param>
public DynamicXmlParser(XElement root)
{
this.root = root;
}
/// <summary>
/// Provides the implementation for operations that get member values.
/// Specifies dynamic behavior for operations such as getting a value for a property.
/// </summary>
/// <param name="binder">
/// Provides information about the object that called the dynamic operation.
/// The binder.Name property provides the name of the member on which the dynamic operation is performed.
/// For example, for the Console.WriteLine(sampleObject.SampleProperty) statement,
/// where sampleObject is an instance of the class derived from the <see cref="T:System.Dynamic.DynamicObject" /> class,
/// binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies whether the member name is case-sensitive.
/// </param>
/// <param name="result">
/// The result of the get operation. For example, if the method is called for a property, you can assign the property value to <paramref name="result" />.
/// </param>
/// <returns>
/// true if the operation is successful; otherwise, false.
/// If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a run-time exception is thrown.)
/// </returns>
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null;
var attribute = root.Attributes().FirstOrDefault(att => att.Name.LocalName.Equals(binder.Name));
if (attribute != null)
{
result = attribute.Value;
return true;
}
var nodesList = root.Elements().Where(el => el.Name.LocalName.Equals(binder.Name));
if (nodesList.Count() > 1)
{
result = nodesList.Select(n => n.HasElements ? (object)new DynamicXmlParser(n) : n.Value).ToList();
return true;
}
else
{
var node = nodesList.FirstOrDefault();
if (node != null)
{
result = node.HasElements ? (object)new DynamicXmlParser(node) : node.Value;
return true;
}
}
return true;
}
/// <summary>
/// Provides implementation for type conversion operations. Classes derived from the <see cref="T:System.Dynamic.DynamicObject" /> class can
/// override this method to specify dynamic behavior for operations that convert an object from one type to another.
/// </summary>
/// <param name="binder">
/// Provides information about the conversion operation. The binder.Type property provides the type to which the object must be converted.
/// For example, for the statement (String)sampleObject, binder.Type returns the <see cref="T:System.String" /> type.
/// The binder.Explicit property provides information about the kind of conversion that occurs.
/// It returns true for explicit conversion and false for implicit conversion.
/// </param>
/// <param name="result">The result of the type conversion operation.</param>
/// <returns>
/// true if the operation is successful; otherwise, false.
/// If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.)
/// </returns>
public override bool TryConvert(ConvertBinder binder, out object result)
{
if (binder.Type == typeof(string) || binder.Type == typeof(String))
{
result = root.ToString();
return true;
}
return base.TryConvert(binder, out result);
}
/// <summary>
/// Returns a <see cref="System.String" /> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String" /> that represents this instance.
/// </returns>
public override string ToString()
{
return root.ToString();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment