PageRenderTime 43ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/Source/Bifrost.Silverlight/Notification/NotifyingObjectWeaver.cs

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