Created
October 13, 2011 20:54
-
-
Save jamietre/1285497 to your computer and use it in GitHub Desktop.
Example ExpandoObject implementation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class JsObject : DynamicObject, IDictionary<string, object>, IEnumerable<KeyValuePair<string, object>> | |
{ | |
public JsObject() | |
{ | |
Initialize(); | |
} | |
public JsObject(object missingPropertyValue) | |
{ | |
Initialize(); | |
MissingPropertyValue = missingPropertyValue; | |
} | |
protected void Initialize() | |
{ | |
AllowMissingProperties = true; | |
MissingPropertyValue = null; | |
IgnoreCase = true; | |
InnerProperties = new Dictionary<string, object>(); | |
} | |
public IEnumerable<T> Enumerate<T>() | |
{ | |
return CsQuery.Enumerate<T>(this); | |
} | |
protected bool AllowMissingProperties | |
{ | |
get; | |
set; | |
} | |
protected object MissingPropertyValue | |
{ | |
get; | |
set; | |
} | |
public bool IgnoreCase | |
{ | |
get; | |
set; | |
} | |
public IDictionary<string, object> InnerProperties | |
{ | |
get; | |
protected set; | |
} | |
protected IDictionary<string, string> NameXref | |
{ | |
get | |
{ | |
return _NameXref.Value; | |
} | |
} | |
private Lazy<Dictionary<string, string>> _NameXref = new Lazy<Dictionary<string, string>>(); | |
public object this[string name] | |
{ | |
get | |
{ | |
object result; | |
TryGetMember(name, typeof(object), out result); | |
return result; | |
} | |
set | |
{ | |
TrySetMember(name, value); | |
} | |
} | |
public T Get<T>(string name) | |
{ | |
object value; | |
TryGetMember(name, typeof(T), out value); | |
return (T)value; | |
} | |
public object Get(string name) | |
{ | |
object value; | |
TryGetMember(name, typeof(object), out value); | |
return value; | |
} | |
public override bool TryGetMember(GetMemberBinder binder, out object result) | |
{ | |
return TryGetMember(binder.Name, binder.ReturnType, out result); | |
} | |
protected bool TryGetMember(string name, Type type, out object result) | |
{ | |
object value = null; | |
if (IgnoreCase) | |
{ | |
NameXref.TryGetValue(name.ToLower(), out name); | |
} | |
bool success = String.IsNullOrEmpty(name) ? false : InnerProperties.TryGetValue(name, out value); | |
if (!success) | |
{ | |
if (AllowMissingProperties) | |
{ | |
if (type == typeof(object)) | |
{ | |
result = MissingPropertyValue; | |
} | |
else | |
{ | |
result = Objects.DefaultValue(type); | |
} | |
success = true; | |
} | |
else | |
{ | |
throw new Exception("There is no property named \"" + name + "\"."); | |
} | |
} | |
else | |
{ | |
if (type == typeof(object)) | |
{ | |
result = value; | |
} | |
else | |
{ | |
result = Objects.Convert(value, type); | |
} | |
} | |
return success; | |
} | |
public override bool TrySetMember(SetMemberBinder binder, object value) | |
{ | |
return TrySetMember(binder.Name, value); | |
} | |
protected bool TrySetMember(string name, object value) | |
{ | |
try | |
{ | |
if (IgnoreCase) | |
{ | |
string realName; | |
if (!NameXref.TryGetValue(name.ToLower(), out realName)) | |
{ | |
NameXref[name.ToLower()] = name; | |
} | |
else | |
{ | |
name = realName; | |
} | |
} | |
if (String.IsNullOrEmpty(name)) | |
{ | |
return false; | |
} | |
if (value is IDictionary<string, object> && !(value is JsObject)) | |
{ | |
InnerProperties[name] = ToJsObject((IDictionary<string, object>)value); | |
} | |
else | |
{ | |
InnerProperties[name] = value; | |
} | |
} | |
catch | |
{ | |
return false; | |
} | |
return true; | |
} | |
public bool HasProperty(string name) | |
{ | |
return InnerProperties.ContainsKey(name); | |
} | |
public bool Delete(string name) | |
{ | |
return InnerProperties.Remove(name); | |
} | |
protected JsObject ToJsObject(IDictionary<string, object> value) | |
{ | |
JsObject obj = new JsObject(); | |
foreach (KeyValuePair<string, object> kvp in value) | |
{ | |
obj[kvp.Key] = kvp.Value; | |
} | |
return obj; | |
} | |
public override IEnumerable<string> GetDynamicMemberNames() | |
{ | |
return InnerProperties.Keys; | |
} | |
public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result) | |
{ | |
throw new Exception("Not supported."); | |
} | |
public IEnumerator<KeyValuePair<string, object>> GetEnumerator() | |
{ | |
return InnerProperties.GetEnumerator(); | |
} | |
IEnumerator IEnumerable.GetEnumerator() | |
{ | |
return GetEnumerator(); | |
} | |
#region Static values | |
public static JsObjectUndefined Undefined | |
{ | |
get | |
{ | |
return new JsObjectUndefined(); | |
} | |
} | |
public static JsObjectDefault Default | |
{ | |
get | |
{ | |
return new JsObjectDefault(); | |
} | |
} | |
#endregion | |
#region explicit interface members | |
void IDictionary<string, object>.Add(string key, object value) | |
{ | |
TrySetMember(key, value); | |
} | |
bool IDictionary<string, object>.ContainsKey(string key) | |
{ | |
return InnerProperties.ContainsKey(key); | |
} | |
ICollection<string> IDictionary<string, object>.Keys | |
{ | |
get { return InnerProperties.Keys; } | |
} | |
bool IDictionary<string, object>.Remove(string key) | |
{ | |
return InnerProperties.Remove(key); | |
} | |
bool IDictionary<string, object>.TryGetValue(string key, out object value) | |
{ | |
return TryGetMember(key, typeof(object), out value); | |
} | |
ICollection<object> IDictionary<string, object>.Values | |
{ | |
get { return InnerProperties.Values; } | |
} | |
void ICollection<KeyValuePair<string, object>>.Add(KeyValuePair<string, object> item) | |
{ | |
TrySetMember(item.Key, item.Value); | |
} | |
void ICollection<KeyValuePair<string, object>>.Clear() | |
{ | |
InnerProperties.Clear(); | |
} | |
bool ICollection<KeyValuePair<string, object>>.Contains(KeyValuePair<string, object> item) | |
{ | |
return InnerProperties.Contains(item); | |
} | |
void ICollection<KeyValuePair<string, object>>.CopyTo(KeyValuePair<string, object>[] array, int arrayIndex) | |
{ | |
InnerProperties.CopyTo(array, arrayIndex); | |
} | |
int ICollection<KeyValuePair<string, object>>.Count | |
{ | |
get { return InnerProperties.Count; } | |
} | |
bool ICollection<KeyValuePair<string, object>>.IsReadOnly | |
{ | |
get { return false; } | |
} | |
bool ICollection<KeyValuePair<string, object>>.Remove(KeyValuePair<string, object> item) | |
{ | |
return InnerProperties.Remove(item); | |
} | |
IEnumerator<KeyValuePair<string, object>> IEnumerable<KeyValuePair<string, object>>.GetEnumerator() | |
{ | |
return GetEnumerator(); | |
} | |
#endregion | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment