PageRenderTime 60ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/Source/Balder/Notification/NotifyingObjectWeaver.cs

#
C# | 496 lines | 389 code | 82 blank | 25 comment | 15 complexity | 4a13db212953e762fa63e7d653daa77f MD5 | raw file
Possible License(s): Apache-2.0
  1. #region License
  2. //
  3. // Author: Einar Ingebrigtsen <einar@dolittle.com>
  4. // Copyright (c) 2007-2011, DoLittle Studios
  5. //
  6. // Licensed under the Microsoft Permissive License (Ms-PL), Version 1.1 (the "License")
  7. // you may not use this file except in compliance with the License.
  8. // You may obtain a copy of the license at
  9. //
  10. // http://balder.codeplex.com/license
  11. //
  12. // Unless required by applicable law or agreed to in writing, software
  13. // distributed under the License is distributed on an "AS IS" BASIS,
  14. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. // See the License for the specific language governing permissions and
  16. // limitations under the License.
  17. //
  18. #endregion
  19. #if(SILVERLIGHT && !WINDOWS_PHONE)
  20. using System;
  21. using System.Collections.Generic;
  22. using System.ComponentModel;
  23. using System.Linq;
  24. using System.Linq.Expressions;
  25. using System.Reflection;
  26. using System.Reflection.Emit;
  27. using System.Runtime.Serialization;
  28. using System.Threading;
  29. using System.Xml.Serialization;
  30. namespace Balder.Notification
  31. {
  32. public class NotifyingObjectWeaver
  33. {
  34. private const string DynamicAssemblyName = "Dynamic Assembly";
  35. private const string DynamicModuleName = "Dynamic Module";
  36. private const string PropertyChangedEventName = "PropertyChanged";
  37. private const string OnPropertyChangedMethodName = "OnPropertyChanged";
  38. private const string DispatcherFieldName = "Dispatcher";
  39. private const string DispatcherManagerCurrentPropertyName = "Current";
  40. private static readonly Type VoidType = typeof(void);
  41. private static readonly Type DelegateType = typeof(Delegate);
  42. private const MethodAttributes EventMethodAttributes =
  43. MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual;
  44. private const MethodAttributes OnPropertyChangedMethodAttributes =
  45. MethodAttributes.Public | MethodAttributes.HideBySig;
  46. private static readonly AssemblyBuilder DynamicAssembly;
  47. private static readonly ModuleBuilder DynamicModule;
  48. private static readonly Dictionary<Type, Type> Proxies = new Dictionary<Type, Type>();
  49. static NotifyingObjectWeaver()
  50. {
  51. var dynamicAssemblyName = CreateUniqueName(DynamicAssemblyName);
  52. var dynamicModuleName = CreateUniqueName(DynamicModuleName);
  53. var appDomain = Thread.GetDomain();
  54. var assemblyName = new AssemblyName(dynamicAssemblyName);
  55. DynamicAssembly = appDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
  56. DynamicModule = DynamicAssembly.DefineDynamicModule(dynamicModuleName, true);
  57. }
  58. public static void ClearTypeCache()
  59. {
  60. Proxies.Clear();
  61. }
  62. public Type GetProxyType<T>()
  63. {
  64. var type = typeof(T);
  65. var proxyType = GetProxyType(type);
  66. return proxyType;
  67. }
  68. public Type GetProxyType(Type type)
  69. {
  70. Type proxyType;
  71. if (Proxies.ContainsKey(type))
  72. {
  73. proxyType = Proxies[type];
  74. }
  75. else
  76. {
  77. proxyType = CreateProxyType(type);
  78. Proxies[type] = proxyType;
  79. }
  80. return proxyType;
  81. }
  82. private static Type CreateProxyType(Type type)
  83. {
  84. var typeBuilder = DefineType(type);
  85. var eventHandlerType = typeof(PropertyChangedEventHandler);
  86. AddAttributesToType(type,typeBuilder);
  87. var propertyChangedFieldBuilder = typeBuilder.DefineField(PropertyChangedEventName, eventHandlerType, FieldAttributes.Private);
  88. var dispatcherFieldBuilder = typeBuilder.DefineField(DispatcherFieldName, typeof(IDispatcher),
  89. FieldAttributes.Private | FieldAttributes.Static);
  90. DefineTypeInitializer(type, typeBuilder, dispatcherFieldBuilder);
  91. DefineConstructorIfNoDefaultConstructorOnBaseType(type, typeBuilder);
  92. OverrideToStringIfNotOverridenInBaseType(type, typeBuilder);
  93. DefineEvent(typeBuilder, eventHandlerType, propertyChangedFieldBuilder);
  94. var onPropertyChangedMethodBuilder = DefineOnPropertyChangedMethod(typeBuilder, eventHandlerType, propertyChangedFieldBuilder, dispatcherFieldBuilder);
  95. DefineProperties(typeBuilder, type, onPropertyChangedMethodBuilder);
  96. var proxyType = typeBuilder.CreateType();
  97. return proxyType;
  98. }
  99. private static void AddAttributesToType(Type type, TypeBuilder typeBuilder)
  100. {
  101. AddAttributeToType<XmlRootAttribute>(typeBuilder,
  102. new Dictionary<string, object>() { { "ElementName", type.Name } });
  103. /*
  104. AddAttributeToType<DataContractAttribute>(typeBuilder,
  105. new Dictionary<string, object>() { { "Name", type.Name } });*/
  106. }
  107. private static void AddAttributeToType<T>(TypeBuilder typeBuilder, IDictionary<string, object> propertiesWithValues)
  108. where T : Attribute
  109. {
  110. var attributeType = typeof (T);
  111. var constructor = attributeType.GetConstructor(new Type[0]);
  112. var properties = new List<PropertyInfo>();
  113. var values = new List<object>();
  114. foreach (var propertyName in propertiesWithValues.Keys)
  115. {
  116. var property = attributeType.GetProperty(propertyName);
  117. properties.Add(property);
  118. values.Add(propertiesWithValues[propertyName]);
  119. }
  120. var attributeBuilder =
  121. new CustomAttributeBuilder(
  122. constructor,
  123. new object[0],
  124. properties.ToArray(),
  125. values.ToArray());
  126. typeBuilder.SetCustomAttribute(attributeBuilder);
  127. }
  128. private static void OverrideToStringIfNotOverridenInBaseType(Type type, TypeBuilder typeBuilder)
  129. {
  130. var toStringMethod = type.GetMethod("ToString");
  131. if ((toStringMethod.Attributes & MethodAttributes.VtableLayoutMask) == MethodAttributes.VtableLayoutMask)
  132. {
  133. var fullName = type.FullName;
  134. var newToStringMethod = typeBuilder.DefineMethod("ToString", toStringMethod.Attributes^MethodAttributes.VtableLayoutMask, typeof(string),
  135. new Type[0]);
  136. var toStringBuilder = newToStringMethod.GetILGenerator();
  137. toStringBuilder.DeclareLocal(typeof (string));
  138. toStringBuilder.Emit(OpCodes.Nop);
  139. toStringBuilder.Emit(OpCodes.Ldstr,fullName);
  140. toStringBuilder.Emit(OpCodes.Stloc_0);
  141. toStringBuilder.Emit(OpCodes.Ldloc_0);
  142. toStringBuilder.Emit(OpCodes.Ret);
  143. typeBuilder.DefineMethodOverride(newToStringMethod,toStringMethod);
  144. }
  145. }
  146. private static void DefineTypeInitializer(Type type, TypeBuilder typeBuilder, FieldBuilder dispatcherFieldBuilder)
  147. {
  148. var constructorBuilder = typeBuilder.DefineTypeInitializer();
  149. var constructorGenerator = constructorBuilder.GetILGenerator();
  150. var dispatcherManagerType = typeof(DispatcherManager);
  151. var currentGetCurrentMethodName = string.Format("get_{0}", DispatcherManagerCurrentPropertyName);
  152. var dispatcherGetCurrentMethod = dispatcherManagerType.GetMethod(currentGetCurrentMethodName);
  153. constructorGenerator.Emit(OpCodes.Call, dispatcherGetCurrentMethod);
  154. constructorGenerator.Emit(OpCodes.Stsfld, dispatcherFieldBuilder);
  155. constructorGenerator.Emit(OpCodes.Ret);
  156. }
  157. private static void DefineConstructorIfNoDefaultConstructorOnBaseType(Type type, TypeBuilder typeBuilder)
  158. {
  159. var constructors = type.GetConstructors();
  160. if (constructors.Length == 1 && constructors[0].GetParameters().Length == 0)
  161. {
  162. DefineDefaultConstructor(type, typeBuilder);
  163. return;
  164. }
  165. foreach (var constructor in constructors)
  166. {
  167. var parameters = constructor.GetParameters().Select(p => p.ParameterType).ToArray();
  168. var constructorBuilder = typeBuilder.DefineConstructor(constructor.Attributes, constructor.CallingConvention, parameters);
  169. var constructorGenerator = constructorBuilder.GetILGenerator();
  170. constructorGenerator.Emit(OpCodes.Ldarg_0);
  171. for (var index = 0; index < parameters.Length; index++)
  172. {
  173. constructorGenerator.Emit(OpCodes.Ldarg, index + 1);
  174. }
  175. constructorGenerator.Emit(OpCodes.Call, constructor);
  176. constructorGenerator.Emit(OpCodes.Nop);
  177. constructorGenerator.Emit(OpCodes.Nop);
  178. constructorGenerator.Emit(OpCodes.Nop);
  179. constructorGenerator.Emit(OpCodes.Ret);
  180. }
  181. }
  182. private static void DefineDefaultConstructor(Type type, TypeBuilder typeBuilder)
  183. {
  184. typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
  185. }
  186. private static void DefineProperties(TypeBuilder typeBuilder, Type baseType, MethodBuilder onPropertyChangedMethodBuilder)
  187. {
  188. var properties = baseType.GetProperties();
  189. var query = from p in properties
  190. where p.GetGetMethod().IsVirtual && !p.GetGetMethod().IsFinal
  191. select p;
  192. var virtualProperties = query.ToArray();
  193. foreach (var property in virtualProperties)
  194. {
  195. if (ShouldPropertyBeIgnored(property))
  196. {
  197. continue;
  198. }
  199. DefineGetMethodForProperty(property, typeBuilder);
  200. DefineSetMethodForProperty(property, typeBuilder, onPropertyChangedMethodBuilder);
  201. }
  202. }
  203. private static bool ShouldPropertyBeIgnored(PropertyInfo propertyInfo)
  204. {
  205. var attributes = propertyInfo.GetCustomAttributes(typeof(IgnoreChangesAttribute), true);
  206. return attributes.Length == 1;
  207. }
  208. private static void DefineSetMethodForProperty(PropertyInfo property, TypeBuilder typeBuilder, MethodBuilder onPropertyChangedMethodBuilder)
  209. {
  210. var setMethodToOverride = property.GetSetMethod();
  211. if (null == setMethodToOverride)
  212. {
  213. return;
  214. }
  215. var setMethodBuilder = typeBuilder.DefineMethod(setMethodToOverride.Name, setMethodToOverride.Attributes, VoidType, new[] { property.PropertyType });
  216. var setMethodGenerator = setMethodBuilder.GetILGenerator();
  217. var propertiesToNotifyFor = GetPropertiesToNotifyFor(property);
  218. setMethodGenerator.Emit(OpCodes.Nop);
  219. setMethodGenerator.Emit(OpCodes.Ldarg_0);
  220. setMethodGenerator.Emit(OpCodes.Ldarg_1);
  221. setMethodGenerator.Emit(OpCodes.Call, setMethodToOverride);
  222. foreach (var propertyName in propertiesToNotifyFor)
  223. {
  224. setMethodGenerator.Emit(OpCodes.Ldarg_0);
  225. setMethodGenerator.Emit(OpCodes.Ldstr, propertyName);
  226. setMethodGenerator.Emit(OpCodes.Call, onPropertyChangedMethodBuilder);
  227. }
  228. setMethodGenerator.Emit(OpCodes.Nop);
  229. setMethodGenerator.Emit(OpCodes.Ret);
  230. typeBuilder.DefineMethodOverride(setMethodBuilder, setMethodToOverride);
  231. }
  232. private static string[] GetPropertiesToNotifyFor(PropertyInfo property)
  233. {
  234. var properties = new List<string>();
  235. properties.Add(property.Name);
  236. var attributes = property.GetCustomAttributes(typeof(NotifyChangesForAttribute), true);
  237. foreach (NotifyChangesForAttribute attribute in attributes)
  238. {
  239. foreach (var propertyName in attribute.PropertyNames)
  240. {
  241. properties.Add(propertyName);
  242. }
  243. }
  244. return properties.ToArray();
  245. }
  246. private static void DefineGetMethodForProperty(PropertyInfo property, TypeBuilder typeBuilder)
  247. {
  248. var getMethodToOverride = property.GetGetMethod();
  249. var getMethodBuilder = typeBuilder.DefineMethod(getMethodToOverride.Name, getMethodToOverride.Attributes, property.PropertyType, new Type[0]);
  250. var getMethodGenerator = getMethodBuilder.GetILGenerator();
  251. var label = getMethodGenerator.DefineLabel();
  252. getMethodGenerator.DeclareLocal(property.PropertyType);
  253. getMethodGenerator.Emit(OpCodes.Nop);
  254. getMethodGenerator.Emit(OpCodes.Ldarg_0);
  255. getMethodGenerator.Emit(OpCodes.Call, getMethodToOverride);
  256. getMethodGenerator.Emit(OpCodes.Stloc_0);
  257. getMethodGenerator.Emit(OpCodes.Br_S, label);
  258. getMethodGenerator.MarkLabel(label);
  259. getMethodGenerator.Emit(OpCodes.Ldloc_0);
  260. getMethodGenerator.Emit(OpCodes.Ret);
  261. typeBuilder.DefineMethodOverride(getMethodBuilder, getMethodToOverride);
  262. }
  263. private static void DefineEvent(TypeBuilder typeBuilder, Type eventHandlerType, FieldBuilder fieldBuilder)
  264. {
  265. var eventBuilder = typeBuilder.DefineEvent("PropertyChanged", EventAttributes.None, eventHandlerType);
  266. DefineAddMethodForEvent(typeBuilder, eventHandlerType, fieldBuilder, eventBuilder);
  267. DefineRemoveMethodForEvent(typeBuilder, eventHandlerType, fieldBuilder, eventBuilder);
  268. }
  269. private static void DefineRemoveMethodForEvent(TypeBuilder typeBuilder, Type eventHandlerType, FieldBuilder fieldBuilder, EventBuilder eventBuilder)
  270. {
  271. var removeEventMethod = string.Format("remove_{0}", PropertyChangedEventName);
  272. var removeMethodInfo = DelegateType.GetMethod("Remove", BindingFlags.Public | BindingFlags.Static, null,
  273. new[] { DelegateType, DelegateType }, null);
  274. var removeMethodBuilder = typeBuilder.DefineMethod(removeEventMethod, EventMethodAttributes, VoidType, new[] { eventHandlerType });
  275. var removeMethodGenerator = removeMethodBuilder.GetILGenerator();
  276. removeMethodGenerator.Emit(OpCodes.Ldarg_0);
  277. removeMethodGenerator.Emit(OpCodes.Ldarg_0);
  278. removeMethodGenerator.Emit(OpCodes.Ldfld, fieldBuilder);
  279. removeMethodGenerator.Emit(OpCodes.Ldarg_1);
  280. removeMethodGenerator.EmitCall(OpCodes.Call, removeMethodInfo, null);
  281. removeMethodGenerator.Emit(OpCodes.Castclass, eventHandlerType);
  282. removeMethodGenerator.Emit(OpCodes.Stfld, fieldBuilder);
  283. removeMethodGenerator.Emit(OpCodes.Ret);
  284. eventBuilder.SetAddOnMethod(removeMethodBuilder);
  285. }
  286. private static void DefineAddMethodForEvent(TypeBuilder typeBuilder, Type eventHandlerType, FieldBuilder fieldBuilder, EventBuilder eventBuilder)
  287. {
  288. var combineMethodInfo = DelegateType.GetMethod("Combine", BindingFlags.Public | BindingFlags.Static, null,
  289. new[] { DelegateType, DelegateType }, null);
  290. var addEventMethod = string.Format("add_{0}", PropertyChangedEventName);
  291. var addMethodBuilder = typeBuilder.DefineMethod(addEventMethod, EventMethodAttributes, VoidType, new[] { eventHandlerType });
  292. var addMethodGenerator = addMethodBuilder.GetILGenerator();
  293. addMethodGenerator.Emit(OpCodes.Ldarg_0);
  294. addMethodGenerator.Emit(OpCodes.Ldarg_0);
  295. addMethodGenerator.Emit(OpCodes.Ldfld, fieldBuilder);
  296. addMethodGenerator.Emit(OpCodes.Ldarg_1);
  297. addMethodGenerator.EmitCall(OpCodes.Call, combineMethodInfo, null);
  298. addMethodGenerator.Emit(OpCodes.Castclass, eventHandlerType);
  299. addMethodGenerator.Emit(OpCodes.Stfld, fieldBuilder);
  300. addMethodGenerator.Emit(OpCodes.Ret);
  301. eventBuilder.SetAddOnMethod(addMethodBuilder);
  302. }
  303. private static MethodInfo GetMethodInfoFromType<T>(Expression<Action<T>> expression)
  304. {
  305. if (expression.Body is MethodCallExpression)
  306. {
  307. var methodCallExpresion = expression.Body as MethodCallExpression;
  308. return methodCallExpresion.Method;
  309. }
  310. return null;
  311. }
  312. private static MethodBuilder DefineOnPropertyChangedMethod(TypeBuilder typeBuilder, Type eventHandlerType, FieldBuilder propertyChangedFieldBuilder, FieldBuilder dispatcherFieldBuilder)
  313. {
  314. var propertyChangedEventArgsType = typeof(PropertyChangedEventArgs);
  315. var onPropertyChangedMethodBuilder = typeBuilder.DefineMethod(OnPropertyChangedMethodName, OnPropertyChangedMethodAttributes, VoidType,
  316. new[] { typeof(string) });
  317. var onPropertyChangedMethodGenerator = onPropertyChangedMethodBuilder.GetILGenerator();
  318. var checkAccessMethod = GetMethodInfoFromType<IDispatcher>(d => d.CheckAccess());
  319. var invokeMethod = GetMethodInfoFromType<PropertyChangedEventHandler>(e => e.Invoke(null, null));
  320. var beginInvokeMethod = GetMethodInfoFromType<IDispatcher>(d => d.BeginInvoke(null, null, null));
  321. var propertyChangedNullLabel = onPropertyChangedMethodGenerator.DefineLabel();
  322. var checkAccessFalseLabel = onPropertyChangedMethodGenerator.DefineLabel();
  323. var doneLabel = onPropertyChangedMethodGenerator.DefineLabel();
  324. onPropertyChangedMethodGenerator.DeclareLocal(typeof(PropertyChangedEventArgs));
  325. onPropertyChangedMethodGenerator.DeclareLocal(typeof(bool));
  326. onPropertyChangedMethodGenerator.DeclareLocal(typeof(object[]));
  327. onPropertyChangedMethodGenerator.Emit(OpCodes.Nop);
  328. // if( null != PropertyChanged )
  329. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldnull);
  330. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldarg_0);
  331. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldfld, propertyChangedFieldBuilder);
  332. onPropertyChangedMethodGenerator.Emit(OpCodes.Ceq);
  333. onPropertyChangedMethodGenerator.Emit(OpCodes.Stloc_1);
  334. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldloc_1);
  335. onPropertyChangedMethodGenerator.Emit(OpCodes.Brtrue_S, propertyChangedNullLabel);
  336. // args = new PropertyChangedEventArgs()
  337. onPropertyChangedMethodGenerator.Emit(OpCodes.Nop);
  338. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldarg_1);
  339. onPropertyChangedMethodGenerator.Emit(OpCodes.Newobj, propertyChangedEventArgsType.GetConstructor(new[] { typeof(string) }));
  340. onPropertyChangedMethodGenerator.Emit(OpCodes.Stloc_0);
  341. // if( Dispatcher.CheckAccess() )
  342. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldsfld, dispatcherFieldBuilder);
  343. onPropertyChangedMethodGenerator.Emit(OpCodes.Callvirt, checkAccessMethod);
  344. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldc_I4_0);
  345. onPropertyChangedMethodGenerator.Emit(OpCodes.Ceq);
  346. onPropertyChangedMethodGenerator.Emit(OpCodes.Stloc_1);
  347. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldloc_1);
  348. onPropertyChangedMethodGenerator.Emit(OpCodes.Brtrue_S, checkAccessFalseLabel);
  349. // CheckAccess == true
  350. // Invoke
  351. onPropertyChangedMethodGenerator.Emit(OpCodes.Nop);
  352. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldarg_0);
  353. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldfld, propertyChangedFieldBuilder);
  354. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldarg_0);
  355. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldloc_0);
  356. onPropertyChangedMethodGenerator.EmitCall(OpCodes.Callvirt, invokeMethod, null);
  357. onPropertyChangedMethodGenerator.Emit(OpCodes.Nop);
  358. onPropertyChangedMethodGenerator.Emit(OpCodes.Nop);
  359. onPropertyChangedMethodGenerator.Emit(OpCodes.Br_S, doneLabel);
  360. // CheckAccess == false
  361. onPropertyChangedMethodGenerator.MarkLabel(checkAccessFalseLabel);
  362. onPropertyChangedMethodGenerator.Emit(OpCodes.Nop);
  363. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldsfld, dispatcherFieldBuilder);
  364. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldarg_0);
  365. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldfld, propertyChangedFieldBuilder);
  366. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldc_I4_2);
  367. onPropertyChangedMethodGenerator.Emit(OpCodes.Newarr, typeof(object));
  368. onPropertyChangedMethodGenerator.Emit(OpCodes.Stloc_2);
  369. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldloc_2);
  370. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldc_I4_0);
  371. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldarg_0);
  372. onPropertyChangedMethodGenerator.Emit(OpCodes.Stelem_Ref);
  373. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldloc_2);
  374. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldc_I4_1);
  375. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldloc_0);
  376. onPropertyChangedMethodGenerator.Emit(OpCodes.Stelem_Ref);
  377. onPropertyChangedMethodGenerator.Emit(OpCodes.Ldloc_2);
  378. onPropertyChangedMethodGenerator.Emit(OpCodes.Callvirt, beginInvokeMethod);
  379. onPropertyChangedMethodGenerator.Emit(OpCodes.Nop);
  380. onPropertyChangedMethodGenerator.Emit(OpCodes.Nop);
  381. onPropertyChangedMethodGenerator.MarkLabel(propertyChangedNullLabel);
  382. onPropertyChangedMethodGenerator.Emit(OpCodes.Nop);
  383. onPropertyChangedMethodGenerator.MarkLabel(doneLabel);
  384. onPropertyChangedMethodGenerator.Emit(OpCodes.Ret);
  385. return onPropertyChangedMethodBuilder;
  386. }
  387. private static TypeBuilder DefineType(Type type)
  388. {
  389. var name = CreateUniqueName(type.Name);
  390. var typeBuilder = DynamicModule.DefineType(name, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Serializable);
  391. AddInterfacesFromBaseType(type, typeBuilder);
  392. typeBuilder.SetParent(type);
  393. var interfaceType = typeof(INotifyPropertyChanged);
  394. typeBuilder.AddInterfaceImplementation(interfaceType);
  395. return typeBuilder;
  396. }
  397. private static void AddInterfacesFromBaseType(Type type, TypeBuilder typeBuilder)
  398. {
  399. var interfaces = type.GetInterfaces();
  400. foreach (var interfaceType in interfaces)
  401. {
  402. typeBuilder.AddInterfaceImplementation(interfaceType);
  403. }
  404. }
  405. private static string CreateUniqueName(string prefix)
  406. {
  407. var uid = Guid.NewGuid().ToString();
  408. uid = uid.Replace('-', '_');
  409. var name = string.Format("{0}{1}", prefix, uid);
  410. return name;
  411. }
  412. }
  413. }
  414. #endif