1
#if !SILVERLIGHT && !PocketPC
3
using System.Collections.Generic;
6
using System.Reflection;
7
using System.Reflection.Emit;
8
using System.Resources;
10
using System.Threading;
11
using System.Globalization;
13
namespace Newtonsoft.Json.Utilities
15
internal class DynamicWrapperBase
17
internal protected object UnderlyingObject;
20
internal static class DynamicWrapper
22
private static readonly object _lock = new object();
23
private static readonly WrapperDictionary _wrapperDictionary = new WrapperDictionary();
25
private static ModuleBuilder _moduleBuilder;
27
private static ModuleBuilder ModuleBuilder
32
return _moduleBuilder;
36
private static void Init()
38
if (_moduleBuilder == null)
42
if (_moduleBuilder == null)
44
AssemblyName assemblyName = new AssemblyName("Newtonsoft.Json.Dynamic");
45
assemblyName.KeyPair = new StrongNameKeyPair(GetStrongKey());
47
AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
48
_moduleBuilder = assembly.DefineDynamicModule("Newtonsoft.Json.DynamicModule", false);
54
private static byte[] GetStrongKey()
56
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Newtonsoft.Json.Dynamic.snk"))
59
throw new MissingManifestResourceException("Should have a Newtonsoft.Json.Dynamic.snk as an embedded resource.");
61
int length = (int)stream.Length;
62
byte[] buffer = new byte[length];
63
stream.Read(buffer, 0, length);
69
public static Type GetWrapper(Type interfaceType, Type realObjectType)
71
Type wrapperType = _wrapperDictionary.GetType(interfaceType, realObjectType);
73
if (wrapperType == null)
75
wrapperType = GenerateWrapperType(interfaceType, realObjectType);
76
_wrapperDictionary.SetType(interfaceType, realObjectType, wrapperType);
82
public static object GetUnderlyingObject(object wrapper)
84
DynamicWrapperBase wrapperBase = wrapper as DynamicWrapperBase;
85
if (wrapperBase == null)
86
throw new ArgumentException("Object is not a wrapper.", "wrapper");
88
return wrapperBase.UnderlyingObject;
91
private static Type GenerateWrapperType(Type interfaceType, Type underlyingType)
93
TypeBuilder wrapperBuilder = ModuleBuilder.DefineType(
94
"{0}_{1}_Wrapper".FormatWith(CultureInfo.InvariantCulture, interfaceType.Name, underlyingType.Name),
95
TypeAttributes.NotPublic | TypeAttributes.Sealed,
96
typeof(DynamicWrapperBase),
97
new[] { interfaceType });
99
WrapperMethodBuilder wrapperMethod = new WrapperMethodBuilder(underlyingType, wrapperBuilder);
101
foreach (MethodInfo method in interfaceType.AllMethods())
103
wrapperMethod.Generate(method);
106
return wrapperBuilder.CreateType();
109
public static T CreateWrapper<T>(object realObject) where T : class
111
var dynamicType = GetWrapper(typeof(T), realObject.GetType());
112
var dynamicWrapper = (DynamicWrapperBase)Activator.CreateInstance(dynamicType);
114
dynamicWrapper.UnderlyingObject = realObject;
116
return dynamicWrapper as T;
120
internal class WrapperMethodBuilder
122
private readonly Type _realObjectType;
123
private readonly TypeBuilder _wrapperBuilder;
125
public WrapperMethodBuilder(Type realObjectType, TypeBuilder proxyBuilder)
127
_realObjectType = realObjectType;
128
_wrapperBuilder = proxyBuilder;
131
public void Generate(MethodInfo newMethod)
133
if (newMethod.IsGenericMethod)
134
newMethod = newMethod.GetGenericMethodDefinition();
136
FieldInfo srcField = typeof(DynamicWrapperBase).GetField("UnderlyingObject", BindingFlags.Instance | BindingFlags.NonPublic);
138
var parameters = newMethod.GetParameters();
139
var parameterTypes = parameters.Select(parameter => parameter.ParameterType).ToArray();
141
MethodBuilder methodBuilder = _wrapperBuilder.DefineMethod(
143
MethodAttributes.Public | MethodAttributes.Virtual,
144
newMethod.ReturnType,
147
if (newMethod.IsGenericMethod)
149
methodBuilder.DefineGenericParameters(
150
newMethod.GetGenericArguments().Select(arg => arg.Name).ToArray());
153
ILGenerator ilGenerator = methodBuilder.GetILGenerator();
155
LoadUnderlyingObject(ilGenerator, srcField);
156
PushParameters(parameters, ilGenerator);
157
ExecuteMethod(newMethod, parameterTypes, ilGenerator);
161
private static void Return(ILGenerator ilGenerator)
163
ilGenerator.Emit(OpCodes.Ret);
166
private void ExecuteMethod(MethodBase newMethod, Type[] parameterTypes, ILGenerator ilGenerator)
168
MethodInfo srcMethod = GetMethod(newMethod, parameterTypes);
170
if (srcMethod == null)
171
throw new MissingMethodException("Unable to find method " + newMethod.Name + " on " + _realObjectType.FullName);
173
ilGenerator.Emit(OpCodes.Call, srcMethod);
176
private MethodInfo GetMethod(MethodBase realMethod, Type[] parameterTypes)
178
if (realMethod.IsGenericMethod)
179
return _realObjectType.GetGenericMethod(realMethod.Name, parameterTypes);
181
return _realObjectType.GetMethod(realMethod.Name, parameterTypes);
184
private static void PushParameters(ICollection<ParameterInfo> parameters, ILGenerator ilGenerator)
186
for (int i = 1; i < parameters.Count + 1; i++)
187
ilGenerator.Emit(OpCodes.Ldarg, i);
190
private static void LoadUnderlyingObject(ILGenerator ilGenerator, FieldInfo srcField)
192
ilGenerator.Emit(OpCodes.Ldarg_0);
193
ilGenerator.Emit(OpCodes.Ldfld, srcField);
197
internal class WrapperDictionary
199
private readonly Dictionary<string, Type> _wrapperTypes = new Dictionary<string, Type>();
201
private static string GenerateKey(Type interfaceType, Type realObjectType)
203
return interfaceType.Name + "_" + realObjectType.Name;
206
public Type GetType(Type interfaceType, Type realObjectType)
208
string key = GenerateKey(interfaceType, realObjectType);
210
if (_wrapperTypes.ContainsKey(key))
211
return _wrapperTypes[key];
216
public void SetType(Type interfaceType, Type realObjectType, Type wrapperType)
218
string key = GenerateKey(interfaceType, realObjectType);
220
if (_wrapperTypes.ContainsKey(key))
221
_wrapperTypes[key] = wrapperType;
223
_wrapperTypes.Add(key, wrapperType);
227
internal static class TypeExtensions
229
public static MethodInfo GetGenericMethod(this Type type, string name, params Type[] parameterTypes)
231
var methods = type.GetMethods().Where(method => method.Name == name);
233
foreach (var method in methods)
235
if (method.HasParameters(parameterTypes))
242
public static bool HasParameters(this MethodInfo method, params Type[] parameterTypes)
244
var methodParameters = method.GetParameters().Select(parameter => parameter.ParameterType).ToArray();
246
if (methodParameters.Length != parameterTypes.Length)
249
for (int i = 0; i < methodParameters.Length; i++)
250
if (methodParameters[i].ToString() != parameterTypes[i].ToString())
256
public static IEnumerable<Type> AllInterfaces(this Type target)
258
foreach (var IF in target.GetInterfaces())
261
foreach (var childIF in IF.AllInterfaces())
263
yield return childIF;
268
public static IEnumerable<MethodInfo> AllMethods(this Type target)
270
var allTypes = target.AllInterfaces().ToList();
271
allTypes.Add(target);
273
return from type in allTypes
274
from method in type.GetMethods()
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 !(SILVERLIGHT || NETFX_CORE || PORTABLE)
28
using System.Collections.Generic;
30
using System.Reflection;
31
using System.Reflection.Emit;
32
using System.Resources;
33
using System.Globalization;
35
using Newtonsoft.Json.Utilities.LinqBridge;
40
namespace Newtonsoft.Json.Utilities
42
internal class DynamicWrapperBase
44
internal protected object UnderlyingObject;
47
internal static class DynamicWrapper
49
private static readonly object _lock = new object();
50
private static readonly WrapperDictionary _wrapperDictionary = new WrapperDictionary();
52
private static ModuleBuilder _moduleBuilder;
54
private static ModuleBuilder ModuleBuilder
59
return _moduleBuilder;
63
private static void Init()
65
if (_moduleBuilder == null)
69
if (_moduleBuilder == null)
71
AssemblyName assemblyName = new AssemblyName("Newtonsoft.Json.Dynamic");
72
assemblyName.KeyPair = new StrongNameKeyPair(GetStrongKey());
74
AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
75
_moduleBuilder = assembly.DefineDynamicModule("Newtonsoft.Json.DynamicModule", false);
81
private static byte[] GetStrongKey()
83
const string name = "Newtonsoft.Json.Dynamic.snk";
85
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name))
88
throw new MissingManifestResourceException("Should have " + name + " as an embedded resource.");
90
int length = (int)stream.Length;
91
byte[] buffer = new byte[length];
92
stream.Read(buffer, 0, length);
98
public static Type GetWrapper(Type interfaceType, Type realObjectType)
100
Type wrapperType = _wrapperDictionary.GetType(interfaceType, realObjectType);
102
if (wrapperType == null)
106
wrapperType = _wrapperDictionary.GetType(interfaceType, realObjectType);
108
if (wrapperType == null)
110
wrapperType = GenerateWrapperType(interfaceType, realObjectType);
111
_wrapperDictionary.SetType(interfaceType, realObjectType, wrapperType);
119
public static object GetUnderlyingObject(object wrapper)
121
DynamicWrapperBase wrapperBase = wrapper as DynamicWrapperBase;
122
if (wrapperBase == null)
123
throw new ArgumentException("Object is not a wrapper.", "wrapper");
125
return wrapperBase.UnderlyingObject;
128
private static Type GenerateWrapperType(Type interfaceType, Type underlyingType)
130
TypeBuilder wrapperBuilder = ModuleBuilder.DefineType(
131
"{0}_{1}_Wrapper".FormatWith(CultureInfo.InvariantCulture, interfaceType.Name, underlyingType.Name),
132
TypeAttributes.NotPublic | TypeAttributes.Sealed,
133
typeof(DynamicWrapperBase),
134
new[] { interfaceType });
136
WrapperMethodBuilder wrapperMethod = new WrapperMethodBuilder(underlyingType, wrapperBuilder);
138
foreach (MethodInfo method in interfaceType.GetAllMethods())
140
wrapperMethod.Generate(method);
143
return wrapperBuilder.CreateType();
146
public static T CreateWrapper<T>(object realObject) where T : class
148
var dynamicType = GetWrapper(typeof(T), realObject.GetType());
149
var dynamicWrapper = (DynamicWrapperBase)Activator.CreateInstance(dynamicType);
151
dynamicWrapper.UnderlyingObject = realObject;
153
return dynamicWrapper as T;
157
internal class WrapperMethodBuilder
159
private readonly Type _realObjectType;
160
private readonly TypeBuilder _wrapperBuilder;
162
public WrapperMethodBuilder(Type realObjectType, TypeBuilder proxyBuilder)
164
_realObjectType = realObjectType;
165
_wrapperBuilder = proxyBuilder;
168
public void Generate(MethodInfo newMethod)
170
if (newMethod.IsGenericMethod)
171
newMethod = newMethod.GetGenericMethodDefinition();
173
FieldInfo srcField = typeof(DynamicWrapperBase).GetField("UnderlyingObject", BindingFlags.Instance | BindingFlags.NonPublic);
175
var parameters = newMethod.GetParameters();
176
var parameterTypes = parameters.Select(parameter => parameter.ParameterType).ToArray();
178
MethodBuilder methodBuilder = _wrapperBuilder.DefineMethod(
180
MethodAttributes.Public | MethodAttributes.Virtual,
181
newMethod.ReturnType,
184
if (newMethod.IsGenericMethod)
186
methodBuilder.DefineGenericParameters(
187
newMethod.GetGenericArguments().Select(arg => arg.Name).ToArray());
190
ILGenerator ilGenerator = methodBuilder.GetILGenerator();
192
LoadUnderlyingObject(ilGenerator, srcField);
193
PushParameters(parameters, ilGenerator);
194
ExecuteMethod(newMethod, parameterTypes, ilGenerator);
198
private static void Return(ILGenerator ilGenerator)
200
ilGenerator.Emit(OpCodes.Ret);
203
private void ExecuteMethod(MethodBase newMethod, Type[] parameterTypes, ILGenerator ilGenerator)
205
MethodInfo srcMethod = GetMethod(newMethod, parameterTypes);
207
if (srcMethod == null)
208
throw new MissingMethodException("Unable to find method " + newMethod.Name + " on " + _realObjectType.FullName);
210
ilGenerator.Emit(OpCodes.Call, srcMethod);
213
private MethodInfo GetMethod(MethodBase realMethod, Type[] parameterTypes)
215
if (realMethod.IsGenericMethod)
216
return _realObjectType.GetGenericMethod(realMethod.Name, parameterTypes);
218
return _realObjectType.GetMethod(realMethod.Name, parameterTypes);
221
private static void PushParameters(ICollection<ParameterInfo> parameters, ILGenerator ilGenerator)
223
for (int i = 1; i < parameters.Count + 1; i++)
224
ilGenerator.Emit(OpCodes.Ldarg, i);
227
private static void LoadUnderlyingObject(ILGenerator ilGenerator, FieldInfo srcField)
229
ilGenerator.Emit(OpCodes.Ldarg_0);
230
ilGenerator.Emit(OpCodes.Ldfld, srcField);
234
internal class WrapperDictionary
236
private readonly Dictionary<string, Type> _wrapperTypes = new Dictionary<string, Type>();
238
private static string GenerateKey(Type interfaceType, Type realObjectType)
240
return interfaceType.Name + "_" + realObjectType.Name;
243
public Type GetType(Type interfaceType, Type realObjectType)
245
string key = GenerateKey(interfaceType, realObjectType);
247
if (_wrapperTypes.ContainsKey(key))
248
return _wrapperTypes[key];
253
public void SetType(Type interfaceType, Type realObjectType, Type wrapperType)
255
string key = GenerateKey(interfaceType, realObjectType);
257
if (_wrapperTypes.ContainsKey(key))
258
_wrapperTypes[key] = wrapperType;
260
_wrapperTypes.Add(key, wrapperType);
b'\\ No newline at end of file'