2
// Copyright (c) 2007 James Newton-King
4
// Permission is hereby granted, free of charge, to any person
5
// obtaining a copy of this software and associated documentation
6
// files (the "Software"), to deal in the Software without
7
// restriction, including without limitation the rights to use,
8
// copy, modify, merge, publish, distribute, sublicense, and/or sell
9
// copies of the Software, and to permit persons to whom the
10
// Software is furnished to do so, subject to the following
13
// The above copyright notice and this permission notice shall be
14
// included in all copies or substantial portions of the Software.
16
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
// OTHER DEALINGS IN THE SOFTWARE.
26
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
28
using System.Collections.Generic;
31
using System.Linq.Expressions;
32
using System.Reflection;
33
using System.Runtime.CompilerServices;
35
using System.Globalization;
36
using Newtonsoft.Json.Serialization;
38
namespace Newtonsoft.Json.Utilities
40
internal static class DynamicUtils
42
internal static class BinderWrapper
45
public const string CSharpAssemblyName = "Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
47
public const string CSharpAssemblyName = "Microsoft.CSharp, Version=2.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
50
private const string BinderTypeName = "Microsoft.CSharp.RuntimeBinder.Binder, " + CSharpAssemblyName;
51
private const string CSharpArgumentInfoTypeName = "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo, " + CSharpAssemblyName;
52
private const string CSharpArgumentInfoFlagsTypeName = "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, " + CSharpAssemblyName;
53
private const string CSharpBinderFlagsTypeName = "Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, " + CSharpAssemblyName;
55
private static object _getCSharpArgumentInfoArray;
56
private static object _setCSharpArgumentInfoArray;
57
private static MethodCall<object, object> _getMemberCall;
58
private static MethodCall<object, object> _setMemberCall;
59
private static bool _init;
61
private static void Init()
65
Type binderType = Type.GetType(BinderTypeName, false);
66
if (binderType == null)
67
throw new InvalidOperationException("Could not resolve type '{0}'. You may need to add a reference to Microsoft.CSharp.dll to work with dynamic types.".FormatWith(CultureInfo.InvariantCulture, BinderTypeName));
70
_getCSharpArgumentInfoArray = CreateSharpArgumentInfoArray(0);
71
// None, Constant | UseCompileTimeType
72
_setCSharpArgumentInfoArray = CreateSharpArgumentInfoArray(0, 3);
79
private static object CreateSharpArgumentInfoArray(params int[] values)
81
Type csharpArgumentInfoType = Type.GetType(CSharpArgumentInfoTypeName);
82
Type csharpArgumentInfoFlags = Type.GetType(CSharpArgumentInfoFlagsTypeName);
84
Array a = Array.CreateInstance(csharpArgumentInfoType, values.Length);
86
for (int i = 0; i < values.Length; i++)
88
MethodInfo createArgumentInfoMethod = csharpArgumentInfoType.GetMethod("Create", BindingFlags.Public | BindingFlags.Static, null, new[] { csharpArgumentInfoFlags, typeof(string) }, null);
89
object arg = createArgumentInfoMethod.Invoke(null, new object[] { 0, null });
96
private static void CreateMemberCalls()
98
Type csharpArgumentInfoType = Type.GetType(CSharpArgumentInfoTypeName);
99
Type csharpBinderFlagsType = Type.GetType(CSharpBinderFlagsTypeName);
100
Type binderType = Type.GetType(BinderTypeName);
102
Type csharpArgumentInfoTypeEnumerableType = typeof(IEnumerable<>).MakeGenericType(csharpArgumentInfoType);
104
MethodInfo getMemberMethod = binderType.GetMethod("GetMember", BindingFlags.Public | BindingFlags.Static, null, new[] { csharpBinderFlagsType, typeof(string), typeof(Type), csharpArgumentInfoTypeEnumerableType }, null);
105
_getMemberCall = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(getMemberMethod);
107
MethodInfo setMemberMethod = binderType.GetMethod("SetMember", BindingFlags.Public | BindingFlags.Static, null, new[] { csharpBinderFlagsType, typeof(string), typeof(Type), csharpArgumentInfoTypeEnumerableType }, null);
108
_setMemberCall = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(setMemberMethod);
111
public static CallSiteBinder GetMember(string name, Type context)
114
return (CallSiteBinder)_getMemberCall(null, 0, name, context, _getCSharpArgumentInfoArray);
117
public static CallSiteBinder SetMember(string name, Type context)
120
return (CallSiteBinder)_setMemberCall(null, 0, name, context, _setCSharpArgumentInfoArray);
124
public static bool TryGetMember(this IDynamicMetaObjectProvider dynamicProvider, string name, out object value)
126
ValidationUtils.ArgumentNotNull(dynamicProvider, "dynamicProvider");
128
GetMemberBinder getMemberBinder = (GetMemberBinder) BinderWrapper.GetMember(name, typeof (DynamicUtils));
130
CallSite<Func<CallSite, object, object>> callSite = CallSite<Func<CallSite, object, object>>.Create(new NoThrowGetBinderMember(getMemberBinder));
132
object result = callSite.Target(callSite, dynamicProvider);
134
if (!ReferenceEquals(result, NoThrowExpressionVisitor.ErrorResult))
146
public static bool TrySetMember(this IDynamicMetaObjectProvider dynamicProvider, string name, object value)
148
ValidationUtils.ArgumentNotNull(dynamicProvider, "dynamicProvider");
150
SetMemberBinder binder = (SetMemberBinder)BinderWrapper.SetMember(name, typeof(DynamicUtils));
152
var setterSite = CallSite<Func<CallSite, object, object, object>>.Create(new NoThrowSetBinderMember(binder));
154
object result = setterSite.Target(setterSite, dynamicProvider, value);
156
return !ReferenceEquals(result, NoThrowExpressionVisitor.ErrorResult);
159
public static IEnumerable<string> GetDynamicMemberNames(this IDynamicMetaObjectProvider dynamicProvider)
161
DynamicMetaObject metaObject = dynamicProvider.GetMetaObject(Expression.Constant(dynamicProvider));
162
return metaObject.GetDynamicMemberNames();
165
internal class NoThrowGetBinderMember : GetMemberBinder
167
private readonly GetMemberBinder _innerBinder;
169
public NoThrowGetBinderMember(GetMemberBinder innerBinder)
170
: base(innerBinder.Name, innerBinder.IgnoreCase)
172
_innerBinder = innerBinder;
175
public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
177
DynamicMetaObject retMetaObject = _innerBinder.Bind(target, new DynamicMetaObject[] { });
179
NoThrowExpressionVisitor noThrowVisitor = new NoThrowExpressionVisitor();
180
Expression resultExpression = noThrowVisitor.Visit(retMetaObject.Expression);
182
DynamicMetaObject finalMetaObject = new DynamicMetaObject(resultExpression, retMetaObject.Restrictions);
183
return finalMetaObject;
187
internal class NoThrowSetBinderMember : SetMemberBinder
189
private readonly SetMemberBinder _innerBinder;
191
public NoThrowSetBinderMember(SetMemberBinder innerBinder)
192
: base(innerBinder.Name, innerBinder.IgnoreCase)
194
_innerBinder = innerBinder;
197
public override DynamicMetaObject FallbackSetMember(DynamicMetaObject target, DynamicMetaObject value, DynamicMetaObject errorSuggestion)
199
DynamicMetaObject retMetaObject = _innerBinder.Bind(target, new DynamicMetaObject[] { value });
201
NoThrowExpressionVisitor noThrowVisitor = new NoThrowExpressionVisitor();
202
Expression resultExpression = noThrowVisitor.Visit(retMetaObject.Expression);
204
DynamicMetaObject finalMetaObject = new DynamicMetaObject(resultExpression, retMetaObject.Restrictions);
205
return finalMetaObject;
210
internal class NoThrowExpressionVisitor : ExpressionVisitor
212
internal static readonly object ErrorResult = new object();
214
protected override Expression VisitConditional(ConditionalExpression node)
216
// if the result of a test is to throw an error, rewrite to result an error result value
217
if (node.IfFalse.NodeType == ExpressionType.Throw)
218
return Expression.Condition(node.Test, node.IfTrue, Expression.Constant(ErrorResult));
220
return base.VisitConditional(node);
b'\\ No newline at end of file'