DelayLoadingTests.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. // -----------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. // -----------------------------------------------------------------------
  4. using System;
  5. using System.Collections.Generic;
  6. using System.ComponentModel.Composition;
  7. using Microsoft.VisualStudio.TestTools.UnitTesting;
  8. using System.ComponentModel.Composition.Factories;
  9. using System.ComponentModel.Composition.UnitTesting;
  10. using System.UnitTesting;
  11. using System.ComponentModel.Composition.AttributedModel;
  12. using System.ComponentModel.Composition.Hosting;
  13. using System.ComponentModel.Composition.Primitives;
  14. using System.Linq;
  15. using System.ComponentModel.Composition.ReflectionModel;
  16. using Microsoft.Internal;
  17. namespace Tests.Integration
  18. {
  19. [TestClass]
  20. public class DelayLoadingTests
  21. {
  22. [TestMethod]
  23. public void PartTypeLoadedLazily()
  24. {
  25. var catalog = new TypeLoadNotifyingCatalog(typeof(ExportingPart));
  26. var container = new CompositionContainer(catalog);
  27. catalog.AssertNotLoaded(typeof(ExportingPart));
  28. Assert.AreEqual(0, catalog.LoadedTypes.Count());
  29. Lazy<IExporter> lazyContract = container.GetExport<IExporter>();
  30. Assert.IsNotNull(lazyContract);
  31. catalog.AssertNotLoaded(typeof(ExportingPart));
  32. Assert.AreEqual(0, catalog.LoadedTypes.Count());
  33. IExporter value = lazyContract.Value;
  34. catalog.AssertLoaded(typeof(ExportingPart));
  35. Assert.AreEqual(1, catalog.LoadedTypes.Count());
  36. }
  37. [TestMethod]
  38. public void PartTypeLoadedLazilyEagerDependeciesLoadEagerly()
  39. {
  40. var catalog = new TypeLoadNotifyingCatalog(typeof(ExportingPart), typeof(PartImportingEagerly));
  41. var container = new CompositionContainer(catalog);
  42. catalog.AssertNotLoaded(typeof(ExportingPart));
  43. catalog.AssertNotLoaded(typeof(PartImportingEagerly));
  44. Assert.AreEqual(0, catalog.LoadedTypes.Count());
  45. Lazy<IImporter> lazyContract = container.GetExport<IImporter>();
  46. Assert.IsNotNull(lazyContract);
  47. catalog.AssertNotLoaded(typeof(PartImportingEagerly));
  48. catalog.AssertNotLoaded(typeof(ExportingPart));
  49. Assert.AreEqual(0, catalog.LoadedTypes.Count());
  50. IImporter value = lazyContract.Value;
  51. catalog.AssertLoaded(typeof(PartImportingEagerly));
  52. catalog.AssertLoaded(typeof(ExportingPart));
  53. Assert.AreEqual(2, catalog.LoadedTypes.Count());
  54. }
  55. [TestMethod]
  56. public void PartTypeLoadedLazilyLazyDependeciesLoadLazily()
  57. {
  58. var catalog = new TypeLoadNotifyingCatalog(typeof(ExportingPart), typeof(PartImportingLazily));
  59. var container = new CompositionContainer(catalog);
  60. catalog.AssertNotLoaded(typeof(ExportingPart));
  61. catalog.AssertNotLoaded(typeof(PartImportingLazily));
  62. Assert.AreEqual(0, catalog.LoadedTypes.Count());
  63. Lazy<IImporter> lazyContract = container.GetExport<IImporter>();
  64. Assert.IsNotNull(lazyContract);
  65. catalog.AssertNotLoaded(typeof(PartImportingLazily));
  66. catalog.AssertNotLoaded(typeof(ExportingPart));
  67. Assert.AreEqual(0, catalog.LoadedTypes.Count());
  68. IImporter value = lazyContract.Value;
  69. catalog.AssertLoaded(typeof(PartImportingLazily));
  70. catalog.AssertNotLoaded(typeof(ExportingPart));
  71. Assert.AreEqual(1, catalog.LoadedTypes.Count());
  72. }
  73. [TestMethod]
  74. public void PartTypeLoadedLazilyEagerCollectionDependeciesLoadEagerly()
  75. {
  76. var catalog = new TypeLoadNotifyingCatalog(typeof(ExportingPart), typeof(PartImportingCollectionEagerly));
  77. var container = new CompositionContainer(catalog);
  78. catalog.AssertNotLoaded(typeof(ExportingPart));
  79. catalog.AssertNotLoaded(typeof(PartImportingCollectionEagerly));
  80. Assert.AreEqual(0, catalog.LoadedTypes.Count());
  81. Lazy<IImporter> lazyContract = container.GetExport<IImporter>();
  82. Assert.IsNotNull(lazyContract);
  83. catalog.AssertNotLoaded(typeof(PartImportingCollectionEagerly));
  84. catalog.AssertNotLoaded(typeof(ExportingPart));
  85. Assert.AreEqual(0, catalog.LoadedTypes.Count());
  86. IImporter value = lazyContract.Value;
  87. catalog.AssertLoaded(typeof(PartImportingCollectionEagerly));
  88. catalog.AssertLoaded(typeof(ExportingPart));
  89. Assert.AreEqual(2, catalog.LoadedTypes.Count());
  90. }
  91. [TestMethod]
  92. public void PartTypeLoadedLazilyLazyCollectionDependeciesLoadLazily()
  93. {
  94. var catalog = new TypeLoadNotifyingCatalog(typeof(ExportingPart), typeof(PartImportingCollectionLazily));
  95. var container = new CompositionContainer(catalog);
  96. catalog.AssertNotLoaded(typeof(ExportingPart));
  97. catalog.AssertNotLoaded(typeof(PartImportingCollectionLazily));
  98. Assert.AreEqual(0, catalog.LoadedTypes.Count());
  99. Lazy<IImporter> lazyContract = container.GetExport<IImporter>();
  100. Assert.IsNotNull(lazyContract);
  101. catalog.AssertNotLoaded(typeof(PartImportingCollectionLazily));
  102. catalog.AssertNotLoaded(typeof(ExportingPart));
  103. Assert.AreEqual(0, catalog.LoadedTypes.Count());
  104. IImporter value = lazyContract.Value;
  105. catalog.AssertLoaded(typeof(PartImportingCollectionLazily));
  106. catalog.AssertNotLoaded(typeof(ExportingPart));
  107. Assert.AreEqual(1, catalog.LoadedTypes.Count());
  108. }
  109. [TestMethod]
  110. public void PartTypeLoadedLazilyLazyLoopLoadsLazily()
  111. {
  112. var catalog = new TypeLoadNotifyingCatalog(typeof(LazyLoopImporter), typeof(LazyLoopExporter));
  113. var container = new CompositionContainer(catalog);
  114. catalog.AssertNotLoaded(typeof(LazyLoopImporter));
  115. catalog.AssertNotLoaded(typeof(LazyLoopExporter));
  116. Assert.AreEqual(0, catalog.LoadedTypes.Count());
  117. Lazy<IImporter> lazyContract = container.GetExport<IImporter>();
  118. Assert.IsNotNull(lazyContract);
  119. catalog.AssertNotLoaded(typeof(LazyLoopImporter));
  120. catalog.AssertNotLoaded(typeof(LazyLoopExporter));
  121. Assert.AreEqual(0, catalog.LoadedTypes.Count());
  122. IImporter value = lazyContract.Value;
  123. catalog.AssertLoaded(typeof(LazyLoopImporter));
  124. catalog.AssertNotLoaded(typeof(LazyLoopExporter));
  125. Assert.AreEqual(1, catalog.LoadedTypes.Count());
  126. }
  127. public class IExporter
  128. {
  129. }
  130. public class IImporter
  131. {
  132. }
  133. [Export(typeof(IExporter))]
  134. public class ExportingPart : IExporter
  135. {
  136. }
  137. [Export(typeof(IImporter))]
  138. public class PartImportingLazily : IImporter
  139. {
  140. [Import]
  141. public Lazy<IExporter> Exporter { get; set; }
  142. }
  143. [Export(typeof(IImporter))]
  144. public class PartImportingCollectionLazily : IImporter
  145. {
  146. [ImportMany]
  147. public IEnumerable<Lazy<IExporter>> Exporters { get; set; }
  148. }
  149. [Export(typeof(IImporter))]
  150. public class PartImportingEagerly : IImporter
  151. {
  152. [Import]
  153. public IExporter Exporter { get; set; }
  154. }
  155. [Export(typeof(IImporter))]
  156. public class PartImportingCollectionEagerly : IImporter
  157. {
  158. [ImportMany]
  159. public IEnumerable<IExporter> Exporters { get; set; }
  160. }
  161. [Export(typeof(IImporter))]
  162. public class LazyLoopImporter : IImporter
  163. {
  164. [Import]
  165. public Lazy<IExporter> Exporter { get; set; }
  166. }
  167. [Export(typeof(IExporter))]
  168. public class LazyLoopExporter : IExporter
  169. {
  170. [Import]
  171. public Lazy<IImporter> Importer { get; set; }
  172. }
  173. private class TypeLoadNotifyingCatalog : ComposablePartCatalog
  174. {
  175. ComposablePartDefinition[] _definitions;
  176. public HashSet<Type> LoadedTypes { get; private set; }
  177. public TypeLoadNotifyingCatalog(params Type[] types)
  178. {
  179. this._definitions = types.Select(type => this.CreatePartDefinition(type)).ToArray();
  180. this.LoadedTypes = new HashSet<Type>();
  181. }
  182. public override IQueryable<ComposablePartDefinition> Parts
  183. {
  184. get { return this._definitions.AsQueryable(); }
  185. }
  186. private ComposablePartDefinition CreatePartDefinition(Type type)
  187. {
  188. ComposablePartDefinition partDefinition = AttributedModelServices.CreatePartDefinition(type, null);
  189. return this.CreateWrapped(partDefinition, type);
  190. }
  191. private ComposablePartDefinition CreateWrapped(ComposablePartDefinition partDefinition, Type type)
  192. {
  193. IEnumerable<ExportDefinition> exports = partDefinition.ExportDefinitions.Select(e => this.CreateWrapped(e, type)).ToArray();
  194. IEnumerable<ImportDefinition> imports = partDefinition.ImportDefinitions.Cast<ContractBasedImportDefinition>().Select(i => this.CreateWrapped(i, type)).ToArray();
  195. return ReflectionModelServices.CreatePartDefinition(
  196. this.CreateWrapped(ReflectionModelServices.GetPartType(partDefinition), type),
  197. ReflectionModelServices.IsDisposalRequired(partDefinition),
  198. imports.AsLazy(),
  199. exports.AsLazy(),
  200. partDefinition.Metadata.AsLazy(),
  201. null);
  202. }
  203. private Lazy<T> CreateWrapped<T>(Lazy<T> lazy, Type type)
  204. {
  205. return new Lazy<T>(
  206. () => { this.OnTypeLoaded(type); return lazy.Value; });
  207. }
  208. private LazyMemberInfo CreateWrapped(LazyMemberInfo lazyMember, Type type)
  209. {
  210. return new LazyMemberInfo(
  211. lazyMember.MemberType,
  212. () => { this.OnTypeLoaded(type); return lazyMember.GetAccessors(); });
  213. }
  214. private ExportDefinition CreateWrapped(ExportDefinition export, Type type)
  215. {
  216. return ReflectionModelServices.CreateExportDefinition(
  217. this.CreateWrapped(ReflectionModelServices.GetExportingMember(export), type),
  218. export.ContractName,
  219. export.Metadata.AsLazy(),
  220. null);
  221. }
  222. private ImportDefinition CreateWrapped(ContractBasedImportDefinition import, Type type)
  223. {
  224. if (ReflectionModelServices.IsImportingParameter(import))
  225. {
  226. return ReflectionModelServices.CreateImportDefinition(
  227. this.CreateWrapped(ReflectionModelServices.GetImportingParameter(import), type),
  228. import.ContractName,
  229. import.RequiredTypeIdentity,
  230. import.RequiredMetadata,
  231. import.Cardinality,
  232. import.RequiredCreationPolicy,
  233. null);
  234. }
  235. else
  236. {
  237. return ReflectionModelServices.CreateImportDefinition(
  238. this.CreateWrapped(ReflectionModelServices.GetImportingMember(import), type),
  239. import.ContractName,
  240. import.RequiredTypeIdentity,
  241. import.RequiredMetadata,
  242. import.Cardinality,
  243. import.IsRecomposable,
  244. import.RequiredCreationPolicy,
  245. null);
  246. }
  247. }
  248. private void OnTypeLoaded(Type type)
  249. {
  250. this.LoadedTypes.Add(type);
  251. }
  252. public void AssertLoaded(Type type)
  253. {
  254. Assert.IsTrue(this.LoadedTypes.Contains(type));
  255. }
  256. public void AssertNotLoaded(Type type)
  257. {
  258. Assert.IsFalse(this.LoadedTypes.Contains(type));
  259. }
  260. }
  261. }
  262. }