update MEF to preview 9
[mcs.git] / class / System.ComponentModel.Composition / Tests / ComponentModelUnitTest / System / ComponentModel / Composition / DynamicMetadata.cs
blob14272bce8e7544a6836ebb7139c79908e08932dd
1 // -----------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 // -----------------------------------------------------------------------
4 using System;
5 using System.Collections.Generic;
6 using System.ComponentModel;
7 using System.ComponentModel.Composition;
8 using System.Linq;
9 using System.Reflection;
10 using Microsoft.VisualStudio.TestTools.UnitTesting;
11 using System.ComponentModel.Composition.Hosting;
13 namespace System.ComponentModel.Composition
15 [TestClass]
16 public class DynamicMetadata
18 [TestMethod]
19 public void SimpleAttachment()
21 MetadataStore.Container = new CompositionContainer();
22 DynamicMetadataTestClass val = DynamicMetadataTestClass.Get("42");
24 var notYetAttached = TypeDescriptor.GetConverter(val);
25 Assert.IsFalse(notYetAttached.CanConvertFrom(typeof(string)), "The default type converter for DynamicMetadataTestClass shouldn't support round tripping");
27 MetadataStore.AddAttribute(
28 typeof(DynamicMetadataTestClass),
29 ( type, attributes) =>
30 Enumerable.Concat(
31 attributes,
32 new Attribute[] { new TypeConverterAttribute(typeof(DynamicMetadataTestClassConverter)) }
35 var attached = TypeDescriptor.GetConverter(val);
36 Assert.IsTrue(attached.CanConvertFrom(typeof(string)), "The new type converter for DynamicMetadataTestClass should support round tripping");
39 [TestMethod]
40 public void LocalContainer()
42 var container1 = new CompositionContainer();
43 TypeDescriptorServices dat = new TypeDescriptorServices();
44 CompositionBatch batch = new CompositionBatch();
45 batch.AddPart(dat);
46 container1.Compose(batch);
47 MetadataStore.AddAttribute(
48 typeof(DynamicMetadataTestClass),
49 ( type, attributes) =>
50 Enumerable.Concat(
51 attributes,
52 new Attribute[] { new TypeConverterAttribute(typeof(DynamicMetadataTestClassConverter)) }
54 container1
56 DynamicMetadataTestClass val = DynamicMetadataTestClass.Get("42");
58 var notYetAttached = TypeDescriptor.GetConverter(val.GetType());
59 Assert.IsFalse(notYetAttached.CanConvertFrom(typeof(string)), "The default type converter for DynamicMetadataTestClass shouldn't support round tripping");
61 var attached = dat.GetConverter(val.GetType());
62 Assert.IsTrue(attached.CanConvertFrom(typeof(string)), "The new type converter for DynamicMetadataTestClass should support round tripping");
65 [TestMethod]
66 public void DualContainers()
68 var container1 = new CompositionContainer();
69 TypeDescriptorServices dat1 = new TypeDescriptorServices();
70 CompositionBatch batch = new CompositionBatch();
71 batch.AddPart(dat1);
72 container1.Compose(batch);
73 MetadataStore.AddAttribute(
74 typeof(DynamicMetadataTestClass),
75 ( type, attributes) =>
76 Enumerable.Concat(
77 attributes,
78 new Attribute[] { new TypeConverterAttribute(typeof(DynamicMetadataTestClassConverter)) }
80 container1
84 var container2 = new CompositionContainer();
85 CompositionBatch batch2 = new CompositionBatch();
86 TypeDescriptorServices dat2 = new TypeDescriptorServices();
87 batch2.AddPart(dat2);
88 container2.Compose(batch2);
90 DynamicMetadataTestClass val = DynamicMetadataTestClass.Get("42");
92 var attached1 = dat1.GetConverter(val.GetType());
93 Assert.IsTrue(attached1.CanConvertFrom(typeof(string)), "The new type converter for DynamicMetadataTestClass should support round tripping");
95 var attached2 = dat2.GetConverter(val.GetType());
96 Assert.IsFalse(attached2.CanConvertFrom(typeof(string)), "The default type converter for DynamicMetadataTestClass shouldn't support round tripping");
99 [TestCleanup]
100 public void ResetContainer()
102 MetadataStore.Container = null;
107 [Export]
108 public class TypeDescriptorServices
110 Dictionary<Type, TypeDescriptionProvider> providers = new Dictionary<Type, TypeDescriptionProvider>();
112 internal Dictionary<Type, TypeDescriptionProvider> Providers
114 get { return providers; }
115 set { providers = value; }
118 public ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
120 if (Providers.ContainsKey(objectType))
122 return Providers[objectType].GetTypeDescriptor(objectType);
124 else
126 return null;
129 public void AddProvider(TypeDescriptionProvider provider, Type type)
131 Providers[type] = provider;
133 public TypeConverter GetConverter(Type type)
135 var ictd = GetTypeDescriptor(type, null);
136 if (ictd != null)
138 return ictd.GetConverter();
140 else
142 return TypeDescriptor.GetConverter(type);
147 public static class MetadataStore
149 public static CompositionContainer Container { get; set; }
150 static Dictionary<Type, TypeDescriptionProvider> registeredRedirect = new Dictionary<Type, TypeDescriptionProvider>();
152 public static void AddAttribute(Type target, Func<MemberInfo, IEnumerable<Attribute>, IEnumerable<Attribute>> provider)
154 AddAttribute(target, provider, MetadataStore.Container);
156 public static void AddAttribute(Type target, Func<MemberInfo, IEnumerable<Attribute>, IEnumerable<Attribute>> provider, CompositionContainer container)
158 ContainerUnawareProviderRedirect.GetRedirect(container)[target] = new MetadataStoreProvider(target, provider);
159 RegisterTypeDescriptorInterop(target);
161 private static void RegisterTypeDescriptorInterop(Type target)
163 if (!registeredRedirect.ContainsKey(target))
165 var r = new ContainerUnawareProviderRedirect(target);
166 TypeDescriptor.AddProvider(r, target);
167 registeredRedirect[target] = r;
169 else
171 // force a uncache of the information from TypeDescriptor
173 TypeDescriptor.RemoveProvider(registeredRedirect[target], target);
174 TypeDescriptor.AddProvider(registeredRedirect[target], target);
177 public static TypeDescriptorServices GetTypeDescriptorServicesForContainer(CompositionContainer container)
179 if (container != null)
181 var result = container.GetExportedValueOrDefault<TypeDescriptorServices>();
182 if (result == null)
184 var v = new TypeDescriptorServices();
185 CompositionBatch batch = new CompositionBatch();
186 batch.AddPart(v);
187 container.Compose(batch);
188 return v;
191 return result;
193 return null;
196 private class ContainerUnawareProviderRedirect : TypeDescriptionProvider
198 public ContainerUnawareProviderRedirect(Type forType)
199 : base(TypeDescriptor.GetProvider(forType))
202 public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
204 var datd = GetTypeDescriptorServicesForContainer(MetadataStore.Container);
205 if (datd == null || !datd.Providers.ContainsKey(objectType))
207 return base.GetTypeDescriptor(objectType, instance);
209 else
211 return datd.GetTypeDescriptor(objectType, instance);
215 internal static Dictionary<Type, TypeDescriptionProvider> GetRedirect(CompositionContainer container)
217 TypeDescriptorServices v = GetTypeDescriptorServicesForContainer(container);
218 return v != null ? v.Providers : null;
222 private class MetadataStoreProvider : TypeDescriptionProvider
224 Func<MemberInfo, IEnumerable<Attribute>, IEnumerable<Attribute>> provider;
225 public MetadataStoreProvider(Type forType, Func<MemberInfo, IEnumerable<Attribute>, IEnumerable<Attribute>> provider)
226 : base(TypeDescriptor.GetProvider(forType))
228 this.provider = provider;
230 public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
232 ICustomTypeDescriptor descriptor = base.GetTypeDescriptor(objectType, instance);
233 descriptor = new MetadataStoreTypeDescriptor(objectType, descriptor, provider);
234 return descriptor;
239 private class MetadataStoreTypeDescriptor : CustomTypeDescriptor
241 Type targetType;
242 Func<MemberInfo, IEnumerable<Attribute>, IEnumerable<Attribute>> provider;
243 public MetadataStoreTypeDescriptor(Type targetType, ICustomTypeDescriptor parent, Func<MemberInfo, IEnumerable<Attribute>, IEnumerable<Attribute>> provider)
244 : base(parent)
246 this.targetType = targetType;
247 this.provider = provider;
249 public override TypeConverter GetConverter()
251 TypeConverterAttribute attribute = (TypeConverterAttribute)GetAttributes()[typeof(TypeConverterAttribute)];
252 if (attribute != null)
254 Type c = this.GetTypeFromName(attribute.ConverterTypeName);
255 if ((c != null) && typeof(TypeConverter).IsAssignableFrom(c))
257 return (TypeConverter)Activator.CreateInstance(c);
260 return base.GetConverter();
262 private Type GetTypeFromName(string typeName)
264 if ((typeName == null) || (typeName.Length == 0))
266 return null;
268 int length = typeName.IndexOf(',');
269 Type type = null;
270 if (length == -1)
272 type = targetType.Assembly.GetType(typeName);
274 if (type == null)
276 type = Type.GetType(typeName);
278 if ((type == null) && (length != -1))
280 type = Type.GetType(typeName.Substring(0, length));
282 return type;
284 public override AttributeCollection GetAttributes()
286 var n = new List<Attribute>();
287 foreach (var attr in provider(targetType, base.GetAttributes().OfType<Attribute>()))
289 n.Add(attr);
291 return new AttributeCollection(n.ToArray());
296 public class DynamicMetadataTestClass
298 int i;
300 private DynamicMetadataTestClass(int i)
302 this.i = i;
305 public override string ToString()
307 return i.ToString();
310 public static DynamicMetadataTestClass Get(string s)
312 return new DynamicMetadataTestClass(Int32.Parse(s));
316 public class DynamicMetadataTestClassConverter : TypeConverter
318 public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
320 return sourceType == typeof(string);
322 public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
324 return ((DynamicMetadataTestClass)value).ToString();
326 public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
328 return DynamicMetadataTestClass.Get((string)value);
330 public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
332 return destinationType == typeof(string);