Skip to content

Instantly share code, notes, and snippets.

@chrisnicola
Created January 26, 2011 18:37
Show Gist options
  • Save chrisnicola/797177 to your computer and use it in GitHub Desktop.
Save chrisnicola/797177 to your computer and use it in GitHub Desktop.
Updated dynamic dictionary with support for implicit casting
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq.Expressions;
using Microsoft.CSharp.RuntimeBinder;
namespace Nancy
{
public class DynamicDictionary : DynamicObject, IEquatable<DynamicDictionary>
{
readonly Dictionary<string, dynamic> dictionary = new Dictionary<string, dynamic>();
public override bool TrySetMember(SetMemberBinder binder, dynamic value)
{
this[binder.Name] = value;
return true;
}
public override bool TryGetMember(GetMemberBinder binder, out dynamic result) { return dictionary.TryGetValue(binder.Name, out result); }
public override IEnumerable<string> GetDynamicMemberNames() { return dictionary.Keys; }
public dynamic this[string name] { get { return dictionary[name]; } set { dictionary[name] = value is DynamicDictionaryValue ? value : new DynamicDictionaryValue(value); } }
/// <summary>
/// Indicates whether the current <see cref = "DynamicDictionary" /> is equal to another object of the same type.
/// </summary>
/// <returns><see langword = "true" /> if the current instance is equal to the <paramref name = "other" /> parameter; otherwise, <see langword = "false" />.</returns>
/// <param name = "other">An <see cref = "DynamicDictionary" /> instance to compare with this instance.</param>
public bool Equals(DynamicDictionary other)
{
if (ReferenceEquals(null, other))
return false;
return ReferenceEquals(this, other) || Equals(other.dictionary, dictionary);
}
/// <summary>
/// Determines whether the specified <see cref = "System.Object" /> is equal to this instance.
/// </summary>
/// <param name = "obj">The <see cref = "System.Object" /> to compare with this instance.</param>
/// <returns><see langword = "true" /> if the specified <see cref = "System.Object" /> is equal to this instance; otherwise, <see langword = "false" />.</returns>
public override bool Equals(dynamic obj)
{
if (ReferenceEquals(null, obj))
return false;
if (ReferenceEquals(this, obj))
return true;
return obj.GetType() == typeof (DynamicDictionary) && Equals((DynamicDictionary) obj);
}
/// <summary>
/// Returns a hash code for this <see cref = "DynamicDictionary" />.
/// </summary>
/// <returns> A hash code for this <see cref = "DynamicDictionary" />, suitable for use in hashing algorithms and data structures like a hash table.</returns>
public override int GetHashCode() { return (dictionary != null ? dictionary.GetHashCode() : 0); }
}
public class DynamicDictionaryValue : DynamicObject
{
readonly dynamic value;
public DynamicDictionaryValue(dynamic value) { this.value = value; }
public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result)
{
object resultOfCast;
result = null;
if (binder.Operation != ExpressionType.Equal)
return false;
var convert =
Binder.Convert(CSharpBinderFlags.None, arg.GetType(), typeof (DynamicDictionaryValue));
if (!TryConvert((ConvertBinder) convert, out resultOfCast))
return false;
result = (resultOfCast == null)
? Equals(arg, resultOfCast)
: resultOfCast.Equals(arg);
return true;
}
public override bool TryConvert(ConvertBinder binder, out dynamic result)
{
result = null;
if (value == null)
return true;
var binderType = binder.Type;
if (binderType == typeof (String))
{
result = Convert.ToString(value);
return true;
}
if (binderType == typeof (Guid) || binderType == typeof (Guid?))
{
Guid guid;
}
else if (binderType == typeof (TimeSpan) || binderType == typeof (TimeSpan?))
{
TimeSpan timespan;
if (TimeSpan.TryParse(Convert.ToString(value), out timespan))
{
result = timespan;
return true;
}
}
else
{
if (binderType.IsGenericType && binderType.GetGenericTypeDefinition() == typeof (Nullable<>))
binderType = binderType.GetGenericArguments()[0];
var typeCode = Type.GetTypeCode(binderType);
if (typeCode == TypeCode.Object) // something went wrong here
return false;
result = Convert.ChangeType(value, typeCode);
return true;
}
return base.TryConvert(binder, out result);
}
public override bool TryUnaryOperation(UnaryOperationBinder binder, out object result) { return base.TryUnaryOperation(binder, out result); }
public override string ToString()
{
if (value == null)
return null;
return Convert.ToString(value);
}
public static implicit operator string(DynamicDictionaryValue d) { return d.ToString(); }
public static implicit operator Guid(DynamicDictionaryValue d)
{
if (d.value is Guid) return d.value;
return Guid.Parse(d.ToString());
}
public static implicit operator int(DynamicDictionaryValue d)
{
if (d.value.GetType().IsValueType) return (int) d.value;
return int.Parse(d.ToString());
}
public static implicit operator long(DynamicDictionaryValue d)
{
if (d.value.GetType().IsValueType) return (long) d.value;
return long.Parse(d.ToString());
}
public static implicit operator float(DynamicDictionaryValue d)
{
if (d.value.GetType().IsValueType) return (float) d.value;
return long.Parse(d.ToString());
}
public static implicit operator double(DynamicDictionaryValue d)
{
if (d.value.GetType().IsValueType) return (double) d.value;
return double.Parse(d.ToString());
}
public static implicit operator decimal(DynamicDictionaryValue d)
{
if (d.value.GetType().IsValueType) return (decimal) d.value;
return decimal.Parse(d.ToString());
}
public static implicit operator TimeSpan(DynamicDictionaryValue d)
{
if (d.value is TimeSpan) return d.value;
return TimeSpan.Parse(d.ToString());
}
public static implicit operator DateTime(DynamicDictionaryValue d)
{
if (d.value is DateTime) return d.value;
return DateTime.Parse(d.ToString());
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment