I wonder why does changing visiblity of DynamicObject-derived class to private prevent the framework from calling TryConvert.
I.e. following code outputs like this:
Calling TryGetMember
Calling TryConvert
But if I change
public sealed class DynamicJsonObject
to private (it's nested within DynamicJsonConverter), then it's
Calling TryGetMember
InvalidCastException is thrown
(Unable to cast object of type 'DynamicJsonObject' to type 'System.Collections.Generic.IDictionary`2[System.String,System.Object]
at CallSite.Target(Closure , CallSite , Object ) at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0))
Code:
void Main()
{
var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new[] { new DynamicJsonConverter() });
dynamic result = serializer.Deserialize("{ 'response' : { 'data' : '1', 's' : -1 } }", typeof(object));
((IDictionary<string, object>)result.response).Dump();
}
public sealed class DynamicJsonConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
return type == typeof(object) ? new DynamicJsonObject(dictionary) : null;
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
public override IEnumerable<Type> SupportedTypes
{
get { return new ReadOnlyCollection<Type>(new List<Type>(new[] { typeof(object) })); }
}
public sealed class DynamicJsonObject : DynamicObject
{
private readonly IDictionary<string, object> _dictionary;
public DynamicJsonObject(IDictionary<string, object> dictionary)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
_dictionary = dictionary;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
Console.WriteLine("Calling TryGetMember");
if (!_dictionary.TryGetValue(binder.Name, out result))
{
result = null;
return true;
}
var dictionary = result as IDictionary<string, object>;
if (dictionary != null)
{
result = new DynamicJsonObject(dictionary);
return true;
}
var arrayList = result as ArrayList;
if (arrayList != null && arrayList.Count > 0)
{
if (arrayList[0] is IDictionary<string, object>)
result = new List<object>(arrayList.Cast<IDictionary<string, object>>().Select(x => new DynamicJsonObject(x)));
else
result = new List<object>(arrayList.Cast<object>());
}
return true;
}
public override bool TryConvert(ConvertBinder binder, out object result)
{
Console.WriteLine("Calling TryConvert");
result = null;
if (binder.Type == typeof(IDictionary<string, object>))
{
result = _dictionary;
return true;
}
return base.TryConvert(binder, out result);
}
}
}