Created
February 1, 2010 20:19
-
-
Save scottwater/291978 to your computer and use it in GitHub Desktop.
This file contains 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
/* | |
* User: scorder | |
* Date: 7/8/2009 | |
* | |
* Updated: 2/1/2010 | |
* User: scottwater | |
* Minor changes to Document to make it play nicely with | |
* C# 4.0 dynamics | |
*/ | |
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Text; | |
using System.Dynamic; | |
namespace MongoDB.Driver { | |
/// <summary> | |
/// Description of Document. | |
/// </summary> | |
public class Document : DynamicObject { | |
//Changed from deriving from Dictionary<string,object> - SW | |
private List<String> orderedKeys = new List<String>(); | |
//Moved dictionary to a prviate instance instead of base class - SW | |
private Dictionary<string, object> Dictionary = new Dictionary<string, object>(); | |
//Dynamic Get Properties - SW | |
public override bool TryGetMember(GetMemberBinder binder, out object result) | |
{ | |
if (Dictionary.ContainsKey(binder.Name)) | |
{ | |
result = Dictionary[binder.Name]; | |
return true; | |
} | |
return base.TryGetMember(binder, out result); | |
} | |
//Dynamic Set Properties - SW | |
public override bool TrySetMember(SetMemberBinder binder, object value) | |
{ | |
this[binder.Name] = value; | |
return true; | |
} | |
public Document() { | |
} | |
public Object this[String key] { | |
get { | |
return Dictionary[key]; | |
} | |
set { | |
if (orderedKeys.Contains(key) == false) { | |
orderedKeys.Add(key); | |
} | |
Dictionary[key] = value; | |
} | |
} | |
public ICollection Keys { | |
get { | |
return (orderedKeys); | |
} | |
} | |
public ICollection Values { | |
get { | |
return (Dictionary.Values); | |
} | |
} | |
public void Add(String key, Object value) { | |
Dictionary.Add(key, value); | |
//Relies on ArgumentException from above if key already exists. | |
orderedKeys.Add(key); | |
} | |
public Document Append(String key, Object value) { | |
this.Add(key, value); | |
return this; | |
} | |
/// <summary> | |
/// Adds an item to the Document at the specified position | |
/// </summary> | |
public void Insert(String key, Object value, int Position){ | |
Dictionary.Add(key, value); | |
//Relies on ArgumentException from above if key already exists. | |
orderedKeys.Insert(Position,key); | |
} | |
public Document Prepend(String key, Object value) { | |
this.Insert(key, value,0); | |
return this; | |
} | |
public Document Update(Document from) { | |
if (from == null) return this; | |
foreach (String key in from.Keys) { | |
this[key] = from[key]; | |
} | |
return this; | |
} | |
public bool Contains(String key) { | |
return (orderedKeys.Contains(key)); | |
} | |
public void Remove(String key) { | |
Dictionary.Remove(key); | |
orderedKeys.Remove(key); | |
} | |
/// <summary> | |
/// TODO Fix any accidental reordering issues. | |
/// </summary> | |
/// <param name="dest"></param> | |
public void CopyTo(Document dest) { | |
foreach (String key in orderedKeys) { | |
dest[key] = this[key]; | |
} | |
} | |
public override bool Equals(object obj) { | |
if (obj is Document) { | |
return Equals(obj as Document); | |
} | |
return base.Equals(obj); | |
} | |
public bool Equals(Document obj) { | |
if (obj == null) | |
return false; | |
if (orderedKeys.Count != obj.orderedKeys.Count) | |
return false; | |
return this.GetHashCode() == obj.GetHashCode(); | |
} | |
public override int GetHashCode() { | |
int hash = 27; | |
foreach (var key in orderedKeys) { | |
var valueHashCode = GetValueHashCode(this[key]); | |
unchecked { | |
hash = (13 * hash) + key.GetHashCode(); | |
hash = (13 * hash) + valueHashCode; | |
} | |
} | |
return hash; | |
} | |
private int GetValueHashCode(object value) { | |
if (value == null) { | |
return 0; | |
} | |
return (value is Array) ? GetArrayHashcode((Array)value) : value.GetHashCode(); | |
} | |
private int GetArrayHashcode(Array array) { | |
var hash = 0; | |
foreach (var value in array) { | |
var valueHashCode = GetValueHashCode(value); | |
unchecked { | |
hash = (13 * hash) + valueHashCode; | |
} | |
} | |
return hash; | |
} | |
public override string ToString() { | |
var json = new StringBuilder(); | |
json.Append("{ "); | |
bool first = true; | |
foreach (String key in orderedKeys) { | |
if (first) { | |
first = false; | |
} else { | |
json.Append(", "); | |
} | |
json.AppendFormat(@"""{0}"": ", key); | |
SerializeType(this[key], json); | |
} | |
json.Append(" }"); | |
return json.ToString(); | |
} | |
private void SerializeType(object value, StringBuilder json) { | |
if (value == null) { | |
json.Append("null"); | |
return; | |
} | |
var t = value.GetType(); | |
if (value is bool) { | |
json.Append(((bool)value) ? "true" : "false"); | |
} else if (t.IsArray) { | |
json.Append("[ "); | |
bool first = true; | |
foreach (var v in (Array)value) { | |
if (first) { | |
first = false; | |
} else { | |
json.Append(", "); | |
} | |
SerializeType(v, json); | |
} | |
json.Append(" ]"); | |
} else if (value is Document || | |
value is Oid || | |
value is int || | |
value is Int32 || | |
value is long || | |
value is float || | |
value is double) { | |
json.Append(value); | |
} else if (value is DateTime) { | |
json.AppendFormat(@"""{0}""", ((DateTime)value).ToUniversalTime().ToString("o")); | |
} else { | |
json.AppendFormat(@"""{0}""", value); | |
} | |
return; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment