1 // -----------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 // -----------------------------------------------------------------------
5 using System
.Collections
.Generic
;
6 using System
.ComponentModel
;
7 using System
.ComponentModel
.Composition
;
9 using System
.Reflection
;
10 using Microsoft
.VisualStudio
.TestTools
.UnitTesting
;
11 using System
.ComponentModel
.Composition
.Hosting
;
13 namespace System
.ComponentModel
.Composition
16 public class DynamicMetadata
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
) =>
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");
40 public void LocalContainer()
42 var container1
= new CompositionContainer();
43 TypeDescriptorServices dat
= new TypeDescriptorServices();
44 CompositionBatch batch
= new CompositionBatch();
46 container1
.Compose(batch
);
47 MetadataStore
.AddAttribute(
48 typeof(DynamicMetadataTestClass
),
49 ( type
, attributes
) =>
52 new Attribute
[] { new TypeConverterAttribute(typeof(DynamicMetadataTestClassConverter)) }
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");
66 public void DualContainers()
68 var container1
= new CompositionContainer();
69 TypeDescriptorServices dat1
= new TypeDescriptorServices();
70 CompositionBatch batch
= new CompositionBatch();
72 container1
.Compose(batch
);
73 MetadataStore
.AddAttribute(
74 typeof(DynamicMetadataTestClass
),
75 ( type
, attributes
) =>
78 new Attribute
[] { new TypeConverterAttribute(typeof(DynamicMetadataTestClassConverter)) }
84 var container2
= new CompositionContainer();
85 CompositionBatch batch2
= new CompositionBatch();
86 TypeDescriptorServices dat2
= new TypeDescriptorServices();
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");
100 public void ResetContainer()
102 MetadataStore
.Container
= null;
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
);
129 public void AddProvider(TypeDescriptionProvider provider
, Type type
)
131 Providers
[type
] = provider
;
133 public TypeConverter
GetConverter(Type type
)
135 var ictd
= GetTypeDescriptor(type
, null);
138 return ictd
.GetConverter();
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
;
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
>();
184 var v
= new TypeDescriptorServices();
185 CompositionBatch batch
= new CompositionBatch();
187 container
.Compose(batch
);
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
);
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
);
239 private class MetadataStoreTypeDescriptor
: CustomTypeDescriptor
242 Func
<MemberInfo
, IEnumerable
<Attribute
>, IEnumerable
<Attribute
>> provider
;
243 public MetadataStoreTypeDescriptor(Type targetType
, ICustomTypeDescriptor parent
, Func
<MemberInfo
, IEnumerable
<Attribute
>, IEnumerable
<Attribute
>> provider
)
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))
268 int length
= typeName
.IndexOf(',');
272 type
= targetType
.Assembly
.GetType(typeName
);
276 type
= Type
.GetType(typeName
);
278 if ((type
== null) && (length
!= -1))
280 type
= Type
.GetType(typeName
.Substring(0, length
));
284 public override AttributeCollection
GetAttributes()
286 var n
= new List
<Attribute
>();
287 foreach (var attr
in provider(targetType
, base.GetAttributes().OfType
<Attribute
>()))
291 return new AttributeCollection(n
.ToArray());
296 public class DynamicMetadataTestClass
300 private DynamicMetadataTestClass(int i
)
305 public override string 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);