1 // Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
2 
3 using System.Collections.Generic;
4 using System.Diagnostics;
5 using System.Dynamic;
6 using System.Globalization;
7 using System.Linq;
8 using System.Web.Helpers.Resources;
9 
10 namespace System.Web.Helpers
11 {
12     // REVIEW: Consider implementing ICustomTypeDescriptor and IDictionary<string, object>
13     public class DynamicJsonObject : DynamicObject
14     {
15         private readonly IDictionary<string, object> _values;
16 
DynamicJsonObject(IDictionary<string, object> values)17         public DynamicJsonObject(IDictionary<string, object> values)
18         {
19             Debug.Assert(values != null);
20             _values = values.ToDictionary(p => p.Key, p => Json.WrapObject(p.Value),
21                                           StringComparer.OrdinalIgnoreCase);
22         }
23 
TryConvert(ConvertBinder binder, out object result)24         public override bool TryConvert(ConvertBinder binder, out object result)
25         {
26             result = null;
27             if (binder.Type.IsAssignableFrom(_values.GetType()))
28             {
29                 result = _values;
30             }
31             else
32             {
33                 throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, HelpersResources.Json_UnableToConvertType, binder.Type));
34             }
35             return true;
36         }
37 
TryGetMember(GetMemberBinder binder, out object result)38         public override bool TryGetMember(GetMemberBinder binder, out object result)
39         {
40             result = GetValue(binder.Name);
41             return true;
42         }
43 
TrySetMember(SetMemberBinder binder, object value)44         public override bool TrySetMember(SetMemberBinder binder, object value)
45         {
46             _values[binder.Name] = Json.WrapObject(value);
47             return true;
48         }
49 
TrySetIndex(SetIndexBinder binder, object[] indexes, object value)50         public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
51         {
52             string key = GetKey(indexes);
53             if (!String.IsNullOrEmpty(key))
54             {
55                 _values[key] = Json.WrapObject(value);
56             }
57             return true;
58         }
59 
TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)60         public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
61         {
62             string key = GetKey(indexes);
63             result = null;
64             if (!String.IsNullOrEmpty(key))
65             {
66                 result = GetValue(key);
67             }
68             return true;
69         }
70 
GetKey(object[] indexes)71         private static string GetKey(object[] indexes)
72         {
73             if (indexes.Length == 1)
74             {
75                 return (string)indexes[0];
76             }
77             // REVIEW: Should this throw?
78             return null;
79         }
80 
GetDynamicMemberNames()81         public override IEnumerable<string> GetDynamicMemberNames()
82         {
83             return _values.Keys;
84         }
85 
GetValue(string name)86         private object GetValue(string name)
87         {
88             object result;
89             if (_values.TryGetValue(name, out result))
90             {
91                 return result;
92             }
93             return null;
94         }
95     }
96 }
97