1 // -----------------------------------------------------------------------
\r
2 // Copyright (c) Microsoft Corporation. All rights reserved.
\r
3 // -----------------------------------------------------------------------
\r
5 using System.Collections.Generic;
\r
6 using System.Collections.Specialized;
\r
7 using System.ComponentModel.Composition.Hosting;
\r
8 using System.ComponentModel.Composition.Primitives;
\r
10 using Microsoft.VisualStudio.TestTools.UnitTesting;
\r
11 using System.ComponentModel.Composition.Factories;
\r
13 namespace System.ComponentModel.Composition
\r
15 public class FilteringCollection<T, M> : AdaptingCollection<T, M>
\r
17 public FilteringCollection(Func<Lazy<T, M>, bool> filter)
\r
18 : base(e => e.Where(filter))
\r
23 public class OrderingCollection<T, M> : AdaptingCollection<T, M>
\r
25 public OrderingCollection(Func<Lazy<T, M>, object> keySelector)
\r
26 : this(keySelector, false)
\r
30 public OrderingCollection(Func<Lazy<T, M>, object> keySelector, bool descending)
\r
31 : base(e => descending ? e.OrderByDescending(keySelector) : e.OrderBy(keySelector))
\r
36 public class AdaptingCollection<T> : AdaptingCollection<T, IDictionary<string, object>>
\r
38 public AdaptingCollection(Func<IEnumerable<Lazy<T, IDictionary<string, object>>>,
\r
39 IEnumerable<Lazy<T, IDictionary<string, object>>>> adaptor)
\r
45 public class AdaptingCollection<T, M> : ICollection<Lazy<T, M>>, INotifyCollectionChanged
\r
47 private readonly List<Lazy<T, M>> _allItems = new List<Lazy<T, M>>();
\r
48 private readonly Func<IEnumerable<Lazy<T, M>>, IEnumerable<Lazy<T, M>>> _adaptor = null;
\r
49 private List<Lazy<T, M>> _adaptedItems = null;
\r
51 public AdaptingCollection() : this(null)
\r
55 public AdaptingCollection(Func<IEnumerable<Lazy<T, M>>, IEnumerable<Lazy<T, M>>> adaptor)
\r
57 this._adaptor = adaptor;
\r
60 public event NotifyCollectionChangedEventHandler CollectionChanged;
\r
62 public void ReapplyAdaptor()
\r
64 if (this._adaptedItems != null)
\r
66 this._adaptedItems = null;
\r
67 this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
\r
71 protected virtual IEnumerable<Lazy<T, M>> Adapt(IEnumerable<Lazy<T, M>> collection)
\r
73 if (this._adaptor != null)
\r
75 return this._adaptor.Invoke(collection);
\r
81 protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
\r
83 NotifyCollectionChangedEventHandler collectionChanged = this.CollectionChanged;
\r
85 if (collectionChanged != null)
\r
87 collectionChanged.Invoke(this, e);
\r
91 private List<Lazy<T, M>> AdaptedItems
\r
95 if (this._adaptedItems == null)
\r
97 this._adaptedItems = Adapt(this._allItems).ToList();
\r
100 return this._adaptedItems;
\r
104 #region ICollection Implementation
\r
105 // Accessors work directly against adapted collection
\r
106 public bool Contains(Lazy<T, M> item)
\r
108 return this.AdaptedItems.Contains(item);
\r
111 public void CopyTo(Lazy<T, M>[] array, int arrayIndex)
\r
113 this.AdaptedItems.CopyTo(array, arrayIndex);
\r
118 get { return this.AdaptedItems.Count; }
\r
121 public bool IsReadOnly
\r
123 get { return false; }
\r
126 public IEnumerator<Lazy<T, M>> GetEnumerator()
\r
128 return this.AdaptedItems.GetEnumerator();
\r
131 Collections.IEnumerator Collections.IEnumerable.GetEnumerator()
\r
133 return this.GetEnumerator();
\r
136 // Mutation methods work against complete collection
\r
137 // and then force a reset of the adapted collection
\r
138 public void Add(Lazy<T, M> item)
\r
140 this._allItems.Add(item);
\r
144 public void Clear()
\r
146 this._allItems.Clear();
\r
150 public bool Remove(Lazy<T, M> item)
\r
152 bool removed = this._allItems.Remove(item);
\r
160 public class AdaptingCollectionTests
\r
162 public interface IContract { }
\r
163 public interface INetworkAwareMetadata
\r
165 [DefaultValue(false)]
\r
166 bool RequiresOnline { get; }
\r
169 [Export(typeof(IContract))]
\r
170 [ExportMetadata("RequiresOnline", true)]
\r
171 public class NetworkExport : IContract { }
\r
173 [Export(typeof(IContract))]
\r
174 public class NonNetworkExport : IContract { }
\r
176 public class FilterExports
\r
178 public FilterExports()
\r
180 this.OnlineOnly = new AdaptingCollection<IContract, INetworkAwareMetadata>(e =>
\r
181 e.Where(p => p.Metadata.RequiresOnline));
\r
183 this.OnlineOnly2 = new FilteringCollection<IContract, INetworkAwareMetadata>(p => p.Metadata.RequiresOnline);
\r
187 public AdaptingCollection<IContract, INetworkAwareMetadata> OnlineOnly { get; set; }
\r
190 public FilteringCollection<IContract, INetworkAwareMetadata> OnlineOnly2 { get; set; }
\r
194 public void TestFilteringImports()
\r
196 var container = ContainerFactory.CreateWithAttributedCatalog(typeof(NetworkExport), typeof(NonNetworkExport));
\r
198 var filterExports = new FilterExports();
\r
199 container.ComposeParts(filterExports);
\r
201 Assert.AreEqual(1, filterExports.OnlineOnly.Count);
\r
202 Assert.AreEqual(1, filterExports.OnlineOnly2.Count);
\r
205 public interface IOrderMetadata
\r
207 [DefaultValue(Int32.MaxValue)]
\r
211 [Export(typeof(IContract))]
\r
212 [ExportMetadata("Order", 2)]
\r
213 public class BExport : IContract { }
\r
215 [Export(typeof(IContract))]
\r
216 [ExportMetadata("Order", 1)]
\r
217 public class AExport : IContract { }
\r
219 [Export(typeof(IContract))]
\r
220 public class CExport : IContract { }
\r
222 public class OrderExportsByMetadata
\r
224 public OrderExportsByMetadata()
\r
226 this.OrderedItems = new AdaptingCollection<IContract, IOrderMetadata>(e =>
\r
227 e.OrderBy(p => p.Metadata.Order));
\r
229 this.OrderedItems2 = new OrderingCollection<IContract, IOrderMetadata>(p => p.Metadata.Order);
\r
233 public AdaptingCollection<IContract, IOrderMetadata> OrderedItems { get; set; }
\r
236 public OrderingCollection<IContract, IOrderMetadata> OrderedItems2 { get; set; }
\r
240 public void TestOrderingImportsByMetadata()
\r
242 var container = ContainerFactory.CreateWithAttributedCatalog(typeof(BExport), typeof(AExport), typeof(CExport));
\r
243 var orderExports = new OrderExportsByMetadata();
\r
245 container.ComposeParts(orderExports);
\r
247 Assert.IsInstanceOfType(orderExports.OrderedItems.ElementAt(0).Value, typeof(AExport));
\r
248 Assert.IsInstanceOfType(orderExports.OrderedItems.ElementAt(1).Value, typeof(BExport));
\r
249 Assert.IsInstanceOfType(orderExports.OrderedItems.ElementAt(2).Value, typeof(CExport));
\r
251 Assert.IsInstanceOfType(orderExports.OrderedItems2.ElementAt(0).Value, typeof(AExport));
\r
252 Assert.IsInstanceOfType(orderExports.OrderedItems2.ElementAt(1).Value, typeof(BExport));
\r
253 Assert.IsInstanceOfType(orderExports.OrderedItems2.ElementAt(2).Value, typeof(CExport));
\r
256 public class OrderExportsByName
\r
258 public OrderExportsByName(bool descending)
\r
262 this.OrderedItems = new AdaptingCollection<IContract>(e =>
\r
263 e.OrderByDescending(p => p.Value.GetType().FullName));
\r
267 this.OrderedItems = new AdaptingCollection<IContract>(e =>
\r
268 e.OrderBy(p => p.Value.GetType().FullName));
\r
273 public AdaptingCollection<IContract> OrderedItems { get; set; }
\r
278 public void TestOrderingImportsByTypeName()
\r
280 var container = ContainerFactory.CreateWithAttributedCatalog(typeof(BExport), typeof(AExport), typeof(CExport));
\r
281 var orderExports = new OrderExportsByName(false);
\r
283 container.ComposeParts(orderExports);
\r
285 Assert.IsInstanceOfType(orderExports.OrderedItems.ElementAt(0).Value, typeof(AExport));
\r
286 Assert.IsInstanceOfType(orderExports.OrderedItems.ElementAt(1).Value, typeof(BExport));
\r
287 Assert.IsInstanceOfType(orderExports.OrderedItems.ElementAt(2).Value, typeof(CExport));
\r
289 orderExports = new OrderExportsByName(true);
\r
291 container.ComposeParts(orderExports);
\r
293 Assert.IsInstanceOfType(orderExports.OrderedItems.ElementAt(0).Value, typeof(CExport));
\r
294 Assert.IsInstanceOfType(orderExports.OrderedItems.ElementAt(1).Value, typeof(BExport));
\r
295 Assert.IsInstanceOfType(orderExports.OrderedItems.ElementAt(2).Value, typeof(AExport));
\r
298 public interface IDynamicFilteredMetadata
\r
300 bool Dynamic { get; }
\r
303 [Export(typeof(IContract))]
\r
304 [ExportMetadata("Dynamic", true)]
\r
305 public class Dynamic1 : IContract { }
\r
307 [Export(typeof(IContract))]
\r
308 [ExportMetadata("Dynamic", true)]
\r
309 public class Dynamic2 : IContract { }
\r
311 [Export(typeof(IContract))]
\r
312 [ExportMetadata("Dynamic", false)]
\r
313 public class NonDynamic1 : IContract { }
\r
315 public class DynamicFilteredCollection<T, M> : AdaptingCollection<T, M> where M : IDynamicFilteredMetadata
\r
317 public DynamicFilteredCollection()
\r
321 private bool _includeDynamic = false;
\r
322 public bool IncludeDynamic
\r
324 get { return this._includeDynamic; }
\r
327 if (this._includeDynamic != value)
\r
329 this.ReapplyAdaptor();
\r
332 this._includeDynamic = value;
\r
336 protected override IEnumerable<Lazy<T, M>> Adapt(IEnumerable<Lazy<T, M>> collection)
\r
338 return collection.Where(p => !p.Metadata.Dynamic || IncludeDynamic);
\r
342 public class DynamicExports
\r
345 public DynamicFilteredCollection<IContract, IDynamicFilteredMetadata> DynamicCollection { get; set; }
\r
349 public void TestDyamicallyFilteringImports()
\r
351 var container = ContainerFactory.CreateWithAttributedCatalog(typeof(Dynamic1), typeof(Dynamic2), typeof(NonDynamic1));
\r
352 var dynamicExports = new DynamicExports();
\r
354 container.ComposeParts(dynamicExports);
\r
356 Assert.AreEqual(1, dynamicExports.DynamicCollection.Count);
\r
358 dynamicExports.DynamicCollection.IncludeDynamic = true;
\r
360 Assert.AreEqual(3, dynamicExports.DynamicCollection.Count);
\r
363 public class DynamicExportsNoSubType
\r
365 public DynamicExportsNoSubType()
\r
367 this.DynamicCollection = new AdaptingCollection<IContract, IDynamicFilteredMetadata>(e =>
\r
368 e.Where(p => !p.Metadata.Dynamic || this.IncludeDynamic));
\r
371 private bool _includeDynamic = false;
\r
372 public bool IncludeDynamic
\r
374 get { return this._includeDynamic; }
\r
377 if (this._includeDynamic != value)
\r
379 this.DynamicCollection.ReapplyAdaptor();
\r
382 this._includeDynamic = value;
\r
387 public AdaptingCollection<IContract, IDynamicFilteredMetadata> DynamicCollection { get; set; }
\r
391 public void TestDyamicallyFilteringNoSubTypeImports()
\r
393 var container = ContainerFactory.CreateWithAttributedCatalog(typeof(Dynamic1), typeof(Dynamic2), typeof(NonDynamic1));
\r
394 var dynamicExports = new DynamicExportsNoSubType();
\r
396 container.ComposeParts(dynamicExports);
\r
398 Assert.AreEqual(1, dynamicExports.DynamicCollection.Count);
\r
400 dynamicExports.IncludeDynamic = true;
\r
402 Assert.AreEqual(3, dynamicExports.DynamicCollection.Count);
\r