Json.NET
Code Coverage Statistics for Source File

Newtonsoft.Json\Utilities\DynamicWrapper.cs

Symbol Coverage: 73.85% (96 of 130)

Branch Coverage: 63.89% (46 of 72)

Cyclomatic Complexity Avg: 1.89 Max:6

Code Lines: 124


L V Source
1
#if !SILVERLIGHT && !PocketPC
2
using System;
3
using System.Collections.Generic;
4
using System.IO;
5
using System.Linq;
6
using System.Reflection;
7
using System.Reflection.Emit;
8
using System.Resources;
9
using System.Text;
10
using System.Threading;
11
using System.Globalization;
12

  
13
namespace Newtonsoft.Json.Utilities
14
{
15
  internal class DynamicWrapperBase
16
  {
17
    internal protected object UnderlyingObject;
18
  }
19

  
20
  internal static class DynamicWrapper
21
  {
22
 1
    private static readonly object _lock = new object();
23
 1
    private static readonly WrapperDictionary _wrapperDictionary = new WrapperDictionary();
24

  
25
    private static ModuleBuilder _moduleBuilder;
26

  
27
    private static ModuleBuilder ModuleBuilder
28
    {
29
      get
30
      {
31
 3
        Init();
32
 3
        return _moduleBuilder;
33
 3
      }
34
    }
35

  
36
    private static void Init()
37
    {
38
 3
      if (_moduleBuilder == null)
39
      {
40
 1
        lock (_lock)
41
        {
42
 1
          if (_moduleBuilder == null)
43
          {
44
 1
            AssemblyName assemblyName = new AssemblyName("Newtonsoft.Json.Dynamic");
45
 1
            assemblyName.KeyPair = new StrongNameKeyPair(GetStrongKey());
46

  
47
 1
            AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
48
 1
            _moduleBuilder = assembly.DefineDynamicModule("Newtonsoft.Json.DynamicModule", false);
49
          }
50
        }
51
      }
52
 3
    }
53

  
54
    private static byte[] GetStrongKey()
55
    {
56
 1
      using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Newtonsoft.Json.Dynamic.snk"))
57
      {
58
 1
        if (stream == null)
59
 0
          throw new MissingManifestResourceException("Should have a Newtonsoft.Json.Dynamic.snk as an embedded resource.");
60

  
61
 1
        int length = (int)stream.Length;
62
 1
        byte[] buffer = new byte[length];
63
 1
        stream.Read(buffer, 0, length);
64

  
65
 1
        return buffer;
66
      }
67
 1
    }
68

  
69
    public static Type GetWrapper(Type interfaceType, Type realObjectType)
70
    {
71
 21
      Type wrapperType = _wrapperDictionary.GetType(interfaceType, realObjectType);
72

  
73
 21
      if (wrapperType == null)
74
      {
75
 3
        wrapperType = GenerateWrapperType(interfaceType, realObjectType);
76
 3
        _wrapperDictionary.SetType(interfaceType, realObjectType, wrapperType);
77
      }
78

  
79
 21
      return wrapperType;
80
 21
    }
81

  
82
    public static object GetUnderlyingObject(object wrapper)
83
    {
84
 8
      DynamicWrapperBase wrapperBase = wrapper as DynamicWrapperBase;
85
 8
      if (wrapperBase == null)
86
 0
        throw new ArgumentException("Object is not a wrapper.", "wrapper");
87

  
88
 8
      return wrapperBase.UnderlyingObject;
89
 8
    }
90

  
91
    private static Type GenerateWrapperType(Type interfaceType, Type underlyingType)
92
    {
93
 3
      TypeBuilder wrapperBuilder = ModuleBuilder.DefineType(
94
 3
          "{0}_{1}_Wrapper".FormatWith(CultureInfo.InvariantCulture, interfaceType.Name, underlyingType.Name),
95
 3
          TypeAttributes.NotPublic | TypeAttributes.Sealed,
96
 3
          typeof(DynamicWrapperBase),
97
 3
          new[] { interfaceType });
98

  
99
 3
      WrapperMethodBuilder wrapperMethod = new WrapperMethodBuilder(underlyingType, wrapperBuilder);
100

  
101
 3
      foreach (MethodInfo method in interfaceType.AllMethods())
102
      {
103
 6
        wrapperMethod.Generate(method);
104
      }
105

  
106
 3
      return wrapperBuilder.CreateType();
107
 3
    }
108

  
109
    public static T CreateWrapper<T>(object realObject) where T : class
110
    {
111
 21
      var dynamicType = GetWrapper(typeof(T), realObject.GetType());
112
 21
      var dynamicWrapper = (DynamicWrapperBase)Activator.CreateInstance(dynamicType);
113

  
114
 21
      dynamicWrapper.UnderlyingObject = realObject;
115

  
116
 21
      return dynamicWrapper as T;
117
 21
    }
118
  }
119

  
120
  internal class WrapperMethodBuilder
121
  {
122
    private readonly Type _realObjectType;
123
    private readonly TypeBuilder _wrapperBuilder;
124

  
125
 3
    public WrapperMethodBuilder(Type realObjectType, TypeBuilder proxyBuilder)
126
    {
127
 3
      _realObjectType = realObjectType;
128
 3
      _wrapperBuilder = proxyBuilder;
129
 3
    }
130

  
131
    public void Generate(MethodInfo newMethod)
132
    {
133
 6
      if (newMethod.IsGenericMethod)
134
 0
        newMethod = newMethod.GetGenericMethodDefinition();
135

  
136
 6
      FieldInfo srcField = typeof(DynamicWrapperBase).GetField("UnderlyingObject", BindingFlags.Instance | BindingFlags.NonPublic);
137

  
138
 6
      var parameters = newMethod.GetParameters();
139
 2
      var parameterTypes = parameters.Select(parameter => parameter.ParameterType).ToArray();
140

  
141
 6
      MethodBuilder methodBuilder = _wrapperBuilder.DefineMethod(
142
 6
          newMethod.Name,
143
 6
          MethodAttributes.Public | MethodAttributes.Virtual,
144
 6
          newMethod.ReturnType,
145
 6
          parameterTypes);
146

  
147
 6
      if (newMethod.IsGenericMethod)
148
      {
149
 0
        methodBuilder.DefineGenericParameters(
150
 0
            newMethod.GetGenericArguments().Select(arg => arg.Name).ToArray());
151
      }
152

  
153
 6
      ILGenerator ilGenerator = methodBuilder.GetILGenerator();
154

  
155
 6
      LoadUnderlyingObject(ilGenerator, srcField);
156
 6
      PushParameters(parameters, ilGenerator);
157
 6
      ExecuteMethod(newMethod, parameterTypes, ilGenerator);
158
 6
      Return(ilGenerator);
159
 6
    }
160

  
161
    private static void Return(ILGenerator ilGenerator)
162
    {
163
 6
      ilGenerator.Emit(OpCodes.Ret);
164
 6
    }
165

  
166
    private void ExecuteMethod(MethodBase newMethod, Type[] parameterTypes, ILGenerator ilGenerator)
167
    {
168
 6
      MethodInfo srcMethod = GetMethod(newMethod, parameterTypes);
169

  
170
 6
      if (srcMethod == null)
171
 0
        throw new MissingMethodException("Unable to find method " + newMethod.Name + " on " + _realObjectType.FullName);
172

  
173
 6
      ilGenerator.Emit(OpCodes.Call, srcMethod);
174
 6
    }
175

  
176
    private MethodInfo GetMethod(MethodBase realMethod, Type[] parameterTypes)
177
    {
178
 6
      if (realMethod.IsGenericMethod)
179
 0
        return _realObjectType.GetGenericMethod(realMethod.Name, parameterTypes);
180

  
181
 6
      return _realObjectType.GetMethod(realMethod.Name, parameterTypes);
182
 6
    }
183

  
184
    private static void PushParameters(ICollection<ParameterInfo> parameters, ILGenerator ilGenerator)
185
    {
186
 2
      for (int i = 1; i < parameters.Count + 1; i++)
187
 2
        ilGenerator.Emit(OpCodes.Ldarg, i);
188
 6
    }
189

  
190
    private static void LoadUnderlyingObject(ILGenerator ilGenerator, FieldInfo srcField)
191
    {
192
 6
      ilGenerator.Emit(OpCodes.Ldarg_0);
193
 6
      ilGenerator.Emit(OpCodes.Ldfld, srcField);
194
 6
    }
195
  }
196

  
197
  internal class WrapperDictionary
198
  {
199
 1
    private readonly Dictionary<string, Type> _wrapperTypes = new Dictionary<string, Type>();
200

  
201
    private static string GenerateKey(Type interfaceType, Type realObjectType)
202
    {
203
 24
      return interfaceType.Name + "_" + realObjectType.Name;
204
 24
    }
205

  
206
    public Type GetType(Type interfaceType, Type realObjectType)
207
    {
208
 21
      string key = GenerateKey(interfaceType, realObjectType);
209

  
210
 21
      if (_wrapperTypes.ContainsKey(key))
211
 18
        return _wrapperTypes[key];
212

  
213
 3
      return null;
214
 21
    }
215

  
216
    public void SetType(Type interfaceType, Type realObjectType, Type wrapperType)
217
    {
218
 3
      string key = GenerateKey(interfaceType, realObjectType);
219

  
220
 3
      if (_wrapperTypes.ContainsKey(key))
221
 0
        _wrapperTypes[key] = wrapperType;
222
      else
223
 3
        _wrapperTypes.Add(key, wrapperType);
224
 3
    }
225
  }
226

  
227
  internal static class TypeExtensions
228
  {
229
    public static MethodInfo GetGenericMethod(this Type type, string name, params Type[] parameterTypes)
230
    {
231
 0
      var methods = type.GetMethods().Where(method => method.Name == name);
232

  
233
 0
      foreach (var method in methods)
234
      {
235
 0
        if (method.HasParameters(parameterTypes))
236
 0
          return method;
237
      }
238

  
239
 0
      return null;
240
 0
    }
241

  
242
    public static bool HasParameters(this MethodInfo method, params Type[] parameterTypes)
243
    {
244
 0
      var methodParameters = method.GetParameters().Select(parameter => parameter.ParameterType).ToArray();
245

  
246
 0
      if (methodParameters.Length != parameterTypes.Length)
247
 0
        return false;
248

  
249
 0
      for (int i = 0; i < methodParameters.Length; i++)
250
 0
        if (methodParameters[i].ToString() != parameterTypes[i].ToString())
251
 0
          return false;
252

  
253
 0
      return true;
254
 0
    }
255

  
256
    public static IEnumerable<Type> AllInterfaces(this Type target)
257
    {
258
 0
      foreach (var IF in target.GetInterfaces())
259
      {
260
 0
        yield return IF;
261
 0
        foreach (var childIF in IF.AllInterfaces())
262
        {
263
 0
          yield return childIF;
264
        }
265
      }
266
    }
267

  
268
    public static IEnumerable<MethodInfo> AllMethods(this Type target)
269
    {
270
 3
      var allTypes = target.AllInterfaces().ToList();
271
 3
      allTypes.Add(target);
272

  
273
 3
      return from type in allTypes
274
 3
             from method in type.GetMethods()
275
 3
             select method;
276
 3
    }
277
  }
278
}
279
#endif