~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/DynamicProxyMetaObject.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
ļ»æ#region License
 
2
// Copyright (c) 2007 James Newton-King
 
3
//
 
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
 
11
// conditions:
 
12
//
 
13
// The above copyright notice and this permission notice shall be
 
14
// included in all copies or substantial portions of the Software.
 
15
//
 
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.
 
24
#endregion
 
25
 
 
26
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
 
27
using System;
 
28
using System.Collections.Generic;
 
29
using System.Dynamic;
 
30
using System.Linq;
 
31
using System.Linq.Expressions;
 
32
using System.Reflection;
 
33
 
 
34
namespace Newtonsoft.Json.Utilities
 
35
{
 
36
  internal sealed class DynamicProxyMetaObject<T> : DynamicMetaObject
 
37
  {
 
38
    private readonly DynamicProxy<T> _proxy;
 
39
    private readonly bool _dontFallbackFirst;
 
40
 
 
41
    internal DynamicProxyMetaObject(Expression expression, T value, DynamicProxy<T> proxy, bool dontFallbackFirst)
 
42
      : base(expression, BindingRestrictions.Empty, value)
 
43
    {
 
44
      _proxy = proxy;
 
45
      _dontFallbackFirst = dontFallbackFirst;
 
46
    }
 
47
 
 
48
    private new T Value { get { return (T)base.Value; } }
 
49
 
 
50
    private bool IsOverridden(string method)
 
51
    {
 
52
      return ReflectionUtils.IsMethodOverridden(_proxy.GetType(), typeof (DynamicProxy<T>), method);
 
53
    }
 
54
 
 
55
    public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
 
56
    {
 
57
      return IsOverridden("TryGetMember")
 
58
           ? CallMethodWithResult("TryGetMember", binder, NoArgs, e => binder.FallbackGetMember(this, e))
 
59
           : base.BindGetMember(binder);
 
60
    }
 
61
 
 
62
    public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)
 
63
    {
 
64
      return IsOverridden("TrySetMember")
 
65
           ? CallMethodReturnLast("TrySetMember", binder, GetArgs(value), e => binder.FallbackSetMember(this, value, e))
 
66
           : base.BindSetMember(binder, value);
 
67
    }
 
68
 
 
69
    public override DynamicMetaObject BindDeleteMember(DeleteMemberBinder binder)
 
70
    {
 
71
      return IsOverridden("TryDeleteMember")
 
72
           ? CallMethodNoResult("TryDeleteMember", binder, NoArgs, e => binder.FallbackDeleteMember(this, e))
 
73
           : base.BindDeleteMember(binder);
 
74
    }
 
75
 
 
76
 
 
77
    public override DynamicMetaObject BindConvert(ConvertBinder binder)
 
78
    {
 
79
      return IsOverridden("TryConvert")
 
80
           ? CallMethodWithResult("TryConvert", binder, NoArgs, e => binder.FallbackConvert(this, e))
 
81
           : base.BindConvert(binder);
 
82
    }
 
83
 
 
84
    public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)
 
85
    {
 
86
      if (!IsOverridden("TryInvokeMember"))
 
87
        return base.BindInvokeMember(binder, args);
 
88
 
 
89
      //
 
90
      // Generate a tree like:
 
91
      //
 
92
      // {
 
93
      //   object result;
 
94
      //   TryInvokeMember(payload, out result)
 
95
      //      ? result
 
96
      //      : TryGetMember(payload, out result)
 
97
      //          ? FallbackInvoke(result)
 
98
      //          : fallbackResult
 
99
      // }
 
100
      //
 
101
      // Then it calls FallbackInvokeMember with this tree as the
 
102
      // "error", giving the language the option of using this
 
103
      // tree or doing .NET binding.
 
104
      //
 
105
      Fallback fallback = e => binder.FallbackInvokeMember(this, args, e);
 
106
 
 
107
      DynamicMetaObject call = BuildCallMethodWithResult(
 
108
          "TryInvokeMember",
 
109
          binder,
 
110
          GetArgArray(args),
 
111
          BuildCallMethodWithResult(
 
112
              "TryGetMember",
 
113
              new GetBinderAdapter(binder),
 
114
              NoArgs,
 
115
              fallback(null),
 
116
              e => binder.FallbackInvoke(e, args, null)
 
117
          ),
 
118
          null
 
119
      );
 
120
 
 
121
      return _dontFallbackFirst ? call : fallback(call);
 
122
    }
 
123
 
 
124
 
 
125
    public override DynamicMetaObject BindCreateInstance(CreateInstanceBinder binder, DynamicMetaObject[] args)
 
126
    {
 
127
      return IsOverridden("TryCreateInstance")
 
128
           ? CallMethodWithResult("TryCreateInstance", binder, GetArgArray(args), e => binder.FallbackCreateInstance(this, args, e))
 
129
           : base.BindCreateInstance(binder, args);
 
130
    }
 
131
 
 
132
    public override DynamicMetaObject BindInvoke(InvokeBinder binder, DynamicMetaObject[] args)
 
133
    {
 
134
      return IsOverridden("TryInvoke")
 
135
        ? CallMethodWithResult("TryInvoke", binder, GetArgArray(args), e => binder.FallbackInvoke(this, args, e))
 
136
        : base.BindInvoke(binder, args);
 
137
    }
 
138
 
 
139
    public override DynamicMetaObject BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg)
 
140
    {
 
141
      return IsOverridden("TryBinaryOperation")
 
142
        ? CallMethodWithResult("TryBinaryOperation", binder, GetArgs(arg), e => binder.FallbackBinaryOperation(this, arg, e))
 
143
        : base.BindBinaryOperation(binder, arg);
 
144
    }
 
145
 
 
146
    public override DynamicMetaObject BindUnaryOperation(UnaryOperationBinder binder)
 
147
    {
 
148
      return IsOverridden("TryUnaryOperation")
 
149
           ? CallMethodWithResult("TryUnaryOperation", binder, NoArgs, e => binder.FallbackUnaryOperation(this, e))
 
150
           : base.BindUnaryOperation(binder);
 
151
    }
 
152
 
 
153
    public override DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes)
 
154
    {
 
155
      return IsOverridden("TryGetIndex")
 
156
           ? CallMethodWithResult("TryGetIndex", binder, GetArgArray(indexes), e => binder.FallbackGetIndex(this, indexes, e))
 
157
           : base.BindGetIndex(binder, indexes);
 
158
    }
 
159
 
 
160
    public override DynamicMetaObject BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value)
 
161
    {
 
162
      return IsOverridden("TrySetIndex")
 
163
           ? CallMethodReturnLast("TrySetIndex", binder, GetArgArray(indexes, value), e => binder.FallbackSetIndex(this, indexes, value, e))
 
164
           : base.BindSetIndex(binder, indexes, value);
 
165
    }
 
166
 
 
167
    public override DynamicMetaObject BindDeleteIndex(DeleteIndexBinder binder, DynamicMetaObject[] indexes)
 
168
    {
 
169
      return IsOverridden("TryDeleteIndex")
 
170
           ? CallMethodNoResult("TryDeleteIndex", binder, GetArgArray(indexes), e => binder.FallbackDeleteIndex(this, indexes, e))
 
171
           : base.BindDeleteIndex(binder, indexes);
 
172
    }
 
173
 
 
174
    private delegate DynamicMetaObject Fallback(DynamicMetaObject errorSuggestion);
 
175
 
 
176
    private readonly static Expression[] NoArgs = new Expression[0];
 
177
 
 
178
    private static Expression[] GetArgs(params DynamicMetaObject[] args)
 
179
    {
 
180
      return args.Select(arg => Expression.Convert(arg.Expression, typeof(object))).ToArray();
 
181
    }
 
182
 
 
183
    private static Expression[] GetArgArray(DynamicMetaObject[] args)
 
184
    {
 
185
      return new[] { Expression.NewArrayInit(typeof(object), GetArgs(args)) };
 
186
    }
 
187
 
 
188
    private static Expression[] GetArgArray(DynamicMetaObject[] args, DynamicMetaObject value)
 
189
    {
 
190
      return new Expression[]
 
191
            {
 
192
                Expression.NewArrayInit(typeof(object), GetArgs(args)),
 
193
                Expression.Convert(value.Expression, typeof(object))
 
194
            };
 
195
    }
 
196
 
 
197
    private static ConstantExpression Constant(DynamicMetaObjectBinder binder)
 
198
    {
 
199
      Type t = binder.GetType();
 
200
      while (!t.IsVisible())
 
201
        t = t.BaseType();
 
202
      return Expression.Constant(binder, t);
 
203
    }
 
204
 
 
205
    /// <summary>
 
206
    /// Helper method for generating a MetaObject which calls a
 
207
    /// specific method on Dynamic that returns a result
 
208
    /// </summary>
 
209
    private DynamicMetaObject CallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, Expression[] args, Fallback fallback, Fallback fallbackInvoke = null)
 
210
    {
 
211
      //
 
212
      // First, call fallback to do default binding
 
213
      // This produces either an error or a call to a .NET member
 
214
      //
 
215
      DynamicMetaObject fallbackResult = fallback(null);
 
216
 
 
217
      DynamicMetaObject callDynamic = BuildCallMethodWithResult(methodName, binder, args, fallbackResult, fallbackInvoke);
 
218
 
 
219
      //
 
220
      // Now, call fallback again using our new MO as the error
 
221
      // When we do this, one of two things can happen:
 
222
      //   1. Binding will succeed, and it will ignore our call to
 
223
      //      the dynamic method, OR
 
224
      //   2. Binding will fail, and it will use the MO we created
 
225
      //      above.
 
226
      //
 
227
 
 
228
      return _dontFallbackFirst ? callDynamic : fallback(callDynamic);
 
229
    }
 
230
 
 
231
    private DynamicMetaObject BuildCallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, Expression[] args, DynamicMetaObject fallbackResult, Fallback fallbackInvoke)
 
232
    {
 
233
      //
 
234
      // Build a new expression like:
 
235
      // {
 
236
      //   object result;
 
237
      //   TryGetMember(payload, out result) ? fallbackInvoke(result) : fallbackResult
 
238
      // }
 
239
      //
 
240
      ParameterExpression result = Expression.Parameter(typeof(object), null);
 
241
 
 
242
      IList<Expression> callArgs = new List<Expression>();
 
243
      callArgs.Add(Expression.Convert(Expression, typeof(T)));
 
244
      callArgs.Add(Constant(binder));
 
245
      callArgs.AddRange(args);
 
246
      callArgs.Add(result);
 
247
 
 
248
      DynamicMetaObject resultMetaObject = new DynamicMetaObject(result, BindingRestrictions.Empty);
 
249
 
 
250
      // Need to add a conversion if calling TryConvert
 
251
      if (binder.ReturnType != typeof (object))
 
252
      {
 
253
        UnaryExpression convert = Expression.Convert(resultMetaObject.Expression, binder.ReturnType);
 
254
        // will always be a cast or unbox
 
255
 
 
256
        resultMetaObject = new DynamicMetaObject(convert, resultMetaObject.Restrictions);
 
257
      }
 
258
 
 
259
      if (fallbackInvoke != null)
 
260
        resultMetaObject = fallbackInvoke(resultMetaObject);
 
261
 
 
262
      DynamicMetaObject callDynamic = new DynamicMetaObject(
 
263
        Expression.Block(
 
264
          new[] {result},
 
265
          Expression.Condition(
 
266
            Expression.Call(
 
267
              Expression.Constant(_proxy),
 
268
              typeof(DynamicProxy<T>).GetMethod(methodName),
 
269
              callArgs
 
270
              ),
 
271
            resultMetaObject.Expression,
 
272
            fallbackResult.Expression,
 
273
            binder.ReturnType
 
274
            )
 
275
          ),
 
276
        GetRestrictions().Merge(resultMetaObject.Restrictions).Merge(fallbackResult.Restrictions)
 
277
        );
 
278
 
 
279
      return callDynamic;
 
280
    }
 
281
 
 
282
    /// <summary>
 
283
    /// Helper method for generating a MetaObject which calls a
 
284
    /// specific method on Dynamic, but uses one of the arguments for
 
285
    /// the result.
 
286
    /// </summary>
 
287
    private DynamicMetaObject CallMethodReturnLast(string methodName, DynamicMetaObjectBinder binder, Expression[] args, Fallback fallback)
 
288
    {
 
289
      //
 
290
      // First, call fallback to do default binding
 
291
      // This produces either an error or a call to a .NET member
 
292
      //
 
293
      DynamicMetaObject fallbackResult = fallback(null);
 
294
 
 
295
      //
 
296
      // Build a new expression like:
 
297
      // {
 
298
      //   object result;
 
299
      //   TrySetMember(payload, result = value) ? result : fallbackResult
 
300
      // }
 
301
      //
 
302
      ParameterExpression result = Expression.Parameter(typeof(object), null);
 
303
 
 
304
      IList<Expression> callArgs = new List<Expression>();
 
305
      callArgs.Add(Expression.Convert(Expression, typeof (T)));
 
306
      callArgs.Add(Constant(binder));
 
307
      callArgs.AddRange(args);
 
308
      callArgs[args.Length + 1] = Expression.Assign(result, callArgs[args.Length + 1]);
 
309
 
 
310
      DynamicMetaObject callDynamic = new DynamicMetaObject(
 
311
          Expression.Block(
 
312
              new[] { result },
 
313
              Expression.Condition(
 
314
                  Expression.Call(
 
315
                      Expression.Constant(_proxy),
 
316
                      typeof(DynamicProxy<T>).GetMethod(methodName),
 
317
                      callArgs
 
318
                  ),
 
319
                  result,
 
320
                  fallbackResult.Expression,
 
321
                  typeof(object)
 
322
              )
 
323
          ),
 
324
          GetRestrictions().Merge(fallbackResult.Restrictions)
 
325
      );
 
326
 
 
327
      //
 
328
      // Now, call fallback again using our new MO as the error
 
329
      // When we do this, one of two things can happen:
 
330
      //   1. Binding will succeed, and it will ignore our call to
 
331
      //      the dynamic method, OR
 
332
      //   2. Binding will fail, and it will use the MO we created
 
333
      //      above.
 
334
      //
 
335
      return _dontFallbackFirst ? callDynamic : fallback(callDynamic);
 
336
    }
 
337
 
 
338
    /// <summary>
 
339
    /// Helper method for generating a MetaObject which calls a
 
340
    /// specific method on Dynamic, but uses one of the arguments for
 
341
    /// the result.
 
342
    /// </summary>
 
343
    private DynamicMetaObject CallMethodNoResult(string methodName, DynamicMetaObjectBinder binder, Expression[] args, Fallback fallback)
 
344
    {
 
345
      //
 
346
      // First, call fallback to do default binding
 
347
      // This produces either an error or a call to a .NET member
 
348
      //
 
349
      DynamicMetaObject fallbackResult = fallback(null);
 
350
 
 
351
      IList<Expression> callArgs = new List<Expression>();
 
352
      callArgs.Add(Expression.Convert(Expression, typeof(T)));
 
353
      callArgs.Add(Constant(binder));
 
354
      callArgs.AddRange(args);
 
355
 
 
356
      //
 
357
      // Build a new expression like:
 
358
      //   if (TryDeleteMember(payload)) { } else { fallbackResult }
 
359
      //
 
360
      DynamicMetaObject callDynamic = new DynamicMetaObject(
 
361
        Expression.Condition(
 
362
          Expression.Call(
 
363
            Expression.Constant(_proxy),
 
364
            typeof(DynamicProxy<T>).GetMethod(methodName),
 
365
            callArgs
 
366
            ),
 
367
          Expression.Empty(),
 
368
          fallbackResult.Expression,
 
369
          typeof (void)
 
370
          ),
 
371
        GetRestrictions().Merge(fallbackResult.Restrictions)
 
372
        );
 
373
 
 
374
      //
 
375
      // Now, call fallback again using our new MO as the error
 
376
      // When we do this, one of two things can happen:
 
377
      //   1. Binding will succeed, and it will ignore our call to
 
378
      //      the dynamic method, OR
 
379
      //   2. Binding will fail, and it will use the MO we created
 
380
      //      above.
 
381
      //
 
382
      return _dontFallbackFirst ? callDynamic : fallback(callDynamic);
 
383
    }
 
384
 
 
385
    /// <summary>
 
386
    /// Returns a Restrictions object which includes our current restrictions merged
 
387
    /// with a restriction limiting our type
 
388
    /// </summary>
 
389
    private BindingRestrictions GetRestrictions()
 
390
    {
 
391
      return (Value == null && HasValue)
 
392
           ? BindingRestrictions.GetInstanceRestriction(Expression, null)
 
393
           : BindingRestrictions.GetTypeRestriction(Expression, LimitType);
 
394
    }
 
395
 
 
396
    public override IEnumerable<string> GetDynamicMemberNames()
 
397
    {
 
398
      return _proxy.GetDynamicMemberNames(Value);
 
399
    }
 
400
 
 
401
    // It is okay to throw NotSupported from this binder. This object
 
402
    // is only used by DynamicObject.GetMember--it is not expected to
 
403
    // (and cannot) implement binding semantics. It is just so the DO
 
404
    // can use the Name and IgnoreCase properties.
 
405
    private sealed class GetBinderAdapter : GetMemberBinder
 
406
    {
 
407
      internal GetBinderAdapter(InvokeMemberBinder binder) :
 
408
        base(binder.Name, binder.IgnoreCase)
 
409
      {
 
410
      }
 
411
 
 
412
      public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
 
413
      {
 
414
        throw new NotSupportedException();
 
415
      }
 
416
    }
 
417
  }
 
418
}
 
419
#endif
 
 
b'\\ No newline at end of file'