1 //------------------------------------------------------------------------------
2 // <copyright file="TypeConverter.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
9 namespace System.ComponentModel {
10 using Microsoft.Win32;
11 using System.Collections;
12 using System.Configuration;
13 using System.ComponentModel.Design.Serialization;
14 using System.Diagnostics;
15 using System.Diagnostics.CodeAnalysis;
16 using System.Globalization;
17 using System.Runtime.InteropServices;
18 using System.Runtime.Remoting;
19 using System.Runtime.Serialization.Formatters;
20 using System.Security.Permissions;
23 /// <para>Converts the value of an object into a different data type.</para>
25 [HostProtection(SharedState = true)]
26 [System.Runtime.InteropServices.ComVisible(true)]
27 public class TypeConverter {
29 private const string s_UseCompatibleTypeConverterBehavior = "UseCompatibleTypeConverterBehavior";
30 private static volatile bool useCompatibleTypeConversion = false;
31 private static volatile bool firstLoadAppSetting = true;
32 private static object loadAppSettingLock = new Object();
34 private static bool UseCompatibleTypeConversion {
37 if (firstLoadAppSetting) {
38 lock (loadAppSettingLock) {
39 if (firstLoadAppSetting) {
40 string useCompatibleConfig = ConfigurationManager.AppSettings[s_UseCompatibleTypeConverterBehavior];
43 if (!String.IsNullOrEmpty(useCompatibleConfig)) {
44 useCompatibleTypeConversion = bool.Parse(useCompatibleConfig.Trim());
48 // we get any exception, then eat out the exception, and use the new TypeConverter.
49 useCompatibleTypeConversion = false;
52 firstLoadAppSetting = false;
57 return useCompatibleTypeConversion;
62 /// <para>Gets a value indicating whether this converter can convert an object in the
63 /// given source type to the native type of the converter.</para>
65 public bool CanConvertFrom(Type sourceType) {
66 return CanConvertFrom(null, sourceType);
70 /// <para>Gets a value indicating whether this converter can
71 /// convert an object in the given source type to the native type of the converter
72 /// using the context.</para>
74 public virtual bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
75 if (sourceType == typeof(InstanceDescriptor)) {
82 /// <para>Gets a value indicating whether this converter can
83 /// convert an object to the given destination type using the context.</para>
85 public bool CanConvertTo(Type destinationType) {
86 return CanConvertTo(null, destinationType);
90 /// <para>Gets a value indicating whether this converter can
91 /// convert an object to the given destination type using the context.</para>
93 public virtual bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
94 return (destinationType == typeof(string));
98 /// <para>Converts the given value
99 /// to the converter's native type.</para>
101 public object ConvertFrom(object value) {
102 return ConvertFrom(null, CultureInfo.CurrentCulture, value);
106 /// <para>Converts the given object to the converter's native type.</para>
108 public virtual object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) {
109 InstanceDescriptor id = value as InstanceDescriptor;
113 throw GetConvertFromException(value);
117 /// Converts the given string to the converter's native type using the invariant culture.
119 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
120 public object ConvertFromInvariantString(string text) {
121 return ConvertFromString(null, CultureInfo.InvariantCulture, text);
125 /// Converts the given string to the converter's native type using the invariant culture.
127 public object ConvertFromInvariantString(ITypeDescriptorContext context, string text) {
128 return ConvertFromString(context, CultureInfo.InvariantCulture, text);
132 /// <para>Converts the specified text into an object.</para>
134 public object ConvertFromString(string text) {
135 return ConvertFrom(null, null, text);
139 /// <para>Converts the specified text into an object.</para>
141 public object ConvertFromString(ITypeDescriptorContext context, string text) {
142 return ConvertFrom(context, CultureInfo.CurrentCulture, text);
146 /// <para>Converts the specified text into an object.</para>
148 public object ConvertFromString(ITypeDescriptorContext context, CultureInfo culture, string text) {
149 return ConvertFrom(context, culture, text);
153 /// <para>Converts the given
154 /// value object to the specified destination type using the arguments.</para>
156 public object ConvertTo(object value, Type destinationType) {
157 return ConvertTo(null, null, value, destinationType);
161 /// <para>Converts the given value object to
162 /// the specified destination type using the specified context and arguments.</para>
164 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] // keep CultureInfo
165 public virtual object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) {
166 if (destinationType == null) {
167 throw new ArgumentNullException("destinationType");
170 if (destinationType == typeof(string)) {
175 // Pre-whidbey we just did a ToString() here. To minimize the chance of a breaking change we
176 // still send requests for the CurrentCulture to ToString() (which should return the same).
177 if(culture != null && culture != CultureInfo.CurrentCulture) {
178 // VSWhidbey 75433 - If the object is IFormattable, use this interface to convert to string
179 // so we use the specified culture rather than the CurrentCulture like object.ToString() does.
180 IFormattable formattable = value as IFormattable;
181 if(formattable != null) {
182 return formattable.ToString(/* format = */ null, /* formatProvider = */ culture);
185 return value.ToString();
187 throw GetConvertToException(value, destinationType);
191 /// <para>Converts the specified value to a culture-invariant string representation.</para>
193 public string ConvertToInvariantString(object value) {
194 return ConvertToString(null, CultureInfo.InvariantCulture, value);
198 /// <para>Converts the specified value to a culture-invariant string representation.</para>
200 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
201 public string ConvertToInvariantString(ITypeDescriptorContext context, object value) {
202 return ConvertToString(context, CultureInfo.InvariantCulture, value);
206 /// <para>Converts the specified value to a string representation.</para>
208 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
209 public string ConvertToString(object value) {
210 return (string)ConvertTo(null, CultureInfo.CurrentCulture, value, typeof(string));
214 /// <para>Converts the specified value to a string representation.</para>
216 public string ConvertToString(ITypeDescriptorContext context, object value) {
217 return (string)ConvertTo(context, CultureInfo.CurrentCulture, value, typeof(string));
221 /// <para>Converts the specified value to a string representation.</para>
223 public string ConvertToString(ITypeDescriptorContext context, CultureInfo culture, object value) {
224 return (string)ConvertTo(context, culture, value, typeof(string));
228 /// <para>Re-creates an <see cref='System.Object'/> given a set of property values for the object.</para>
230 public object CreateInstance(IDictionary propertyValues) {
231 return CreateInstance(null, propertyValues);
235 /// <para>Re-creates an <see cref='System.Object'/> given a set of property values for the
238 public virtual object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues) {
244 /// Gets a suitable exception to throw when a conversion cannot
248 protected Exception GetConvertFromException(object value) {
249 string valueTypeName;
252 valueTypeName = SR.GetString(SR.ToStringNull);
255 valueTypeName = value.GetType().FullName;
258 throw new NotSupportedException(SR.GetString(SR.ConvertFromException, GetType().Name, valueTypeName));
262 /// <para>Retrieves a suitable exception to throw when a conversion cannot
263 /// be performed.</para>
265 protected Exception GetConvertToException(object value, Type destinationType) {
266 string valueTypeName;
269 valueTypeName = SR.GetString(SR.ToStringNull);
272 valueTypeName = value.GetType().FullName;
275 throw new NotSupportedException(SR.GetString(SR.ConvertToException, GetType().Name, valueTypeName, destinationType.FullName));
279 /// <para>Gets a value indicating whether changing a value on this
280 /// object requires a call to <see cref='System.ComponentModel.TypeConverter.CreateInstance'/>
281 /// to create a new value.</para>
283 public bool GetCreateInstanceSupported() {
284 return GetCreateInstanceSupported(null);
288 /// <para>Gets a value indicating whether changing a value on this object requires a
289 /// call to <see cref='System.ComponentModel.TypeConverter.CreateInstance'/> to create a new value,
290 /// using the specified context.</para>
292 public virtual bool GetCreateInstanceSupported(ITypeDescriptorContext context) {
297 /// <para>Gets a collection of properties for the type of array specified by the value
298 /// parameter.</para>
300 public PropertyDescriptorCollection GetProperties(object value) {
301 return GetProperties(null, value);
305 /// <para>Gets a collection of
306 /// properties for the type of array specified by the value parameter using the specified
309 public PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value) {
310 return GetProperties(context, value, new Attribute[] {BrowsableAttribute.Yes});
314 /// <para>Gets a collection of properties for
315 /// the type of array specified by the value parameter using the specified context and
316 /// attributes.</para>
318 public virtual PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) {
324 /// Gets a value indicating whether this object supports properties.
327 public bool GetPropertiesSupported() {
328 return GetPropertiesSupported(null);
332 /// <para>Gets a value indicating
333 /// whether this object supports properties using the
334 /// specified context.</para>
336 public virtual bool GetPropertiesSupported(ITypeDescriptorContext context) {
341 /// <para> Gets a collection of standard values for the data type this type
342 /// converter is designed for.</para>
344 public ICollection GetStandardValues() {
345 return GetStandardValues(null);
349 /// <para>Gets a collection of standard values for the data type this type converter is
350 /// designed for.</para>
352 public virtual StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) {
357 /// <para>Gets a value indicating whether the collection of standard values returned from
358 /// <see cref='System.ComponentModel.TypeConverter.GetStandardValues'/> is an exclusive list. </para>
360 public bool GetStandardValuesExclusive() {
361 return GetStandardValuesExclusive(null);
365 /// <para>Gets a value indicating whether the collection of standard values returned from
366 /// <see cref='System.ComponentModel.TypeConverter.GetStandardValues'/> is an exclusive
367 /// list of possible values, using the specified context.</para>
369 public virtual bool GetStandardValuesExclusive(ITypeDescriptorContext context) {
375 /// Gets a value indicating whether this object supports a standard set of values
376 /// that can be picked from a list.
379 public bool GetStandardValuesSupported() {
380 return GetStandardValuesSupported(null);
384 /// <para>Gets a value indicating
385 /// whether this object
386 /// supports a standard set of values that can be picked
387 /// from a list using the specified context.</para>
389 public virtual bool GetStandardValuesSupported(ITypeDescriptorContext context) {
396 /// a value indicating whether the given value object is valid for this type.
399 public bool IsValid(object value) {
400 return IsValid(null, value);
405 /// a value indicating whether the given value object is valid for this type.</para>
407 public virtual bool IsValid(ITypeDescriptorContext context, object value) {
408 if (UseCompatibleTypeConversion) {
414 // Because null doesn't have a type, so we couldn't pass this to CanConvertFrom.
415 // Meanwhile, we couldn't silence null value here, such as type converter like
416 // NullableConverter would consider null value as a valid value.
417 if (value == null || CanConvertFrom(context, value.GetType())) {
418 ConvertFrom(context, CultureInfo.InvariantCulture, value);
432 /// <para>Sorts a collection of properties.</para>
434 protected PropertyDescriptorCollection SortProperties(PropertyDescriptorCollection props, string[] names) {
441 /// An <see langword='abstract '/>
442 /// class that provides
443 /// properties for objects that do not have
447 protected abstract class SimplePropertyDescriptor : PropertyDescriptor {
448 private Type componentType;
449 private Type propertyType;
454 /// Initializes a new instance of the <see cref='System.ComponentModel.TypeConverter.SimplePropertyDescriptor'/>
458 protected SimplePropertyDescriptor(Type componentType, string name, Type propertyType) : this(componentType, name, propertyType, new Attribute[0]) {
463 /// Initializes a new instance of the <see cref='System.ComponentModel.TypeConverter.SimplePropertyDescriptor'/> class.
466 protected SimplePropertyDescriptor(Type componentType, string name, Type propertyType, Attribute[] attributes) : base(name, attributes) {
467 this.componentType = componentType;
468 this.propertyType = propertyType;
473 /// Gets the type of the component this property description
477 public override Type ComponentType {
479 return componentType;
486 /// value indicating whether this property is read-only.
489 public override bool IsReadOnly {
491 return Attributes.Contains(ReadOnlyAttribute.Yes);
497 /// Gets the type of the property.
500 public override Type PropertyType {
507 /// <para>Gets a value indicating whether resetting the component
508 /// will change the value of the component.</para>
510 public override bool CanResetValue(object component) {
511 DefaultValueAttribute attr = (DefaultValueAttribute)Attributes[typeof(DefaultValueAttribute)];
515 return (attr.Value.Equals(GetValue(component)));
519 /// <para>Resets the value for this property
520 /// of the component.</para>
522 public override void ResetValue(object component) {
523 DefaultValueAttribute attr = (DefaultValueAttribute)Attributes[typeof(DefaultValueAttribute)];
525 SetValue(component, attr.Value);
530 /// <para>Gets a value
531 /// indicating whether the value of this property needs to be persisted.</para>
533 public override bool ShouldSerializeValue(object component) {
539 /// <para>Represents a collection of values.</para>
541 public class StandardValuesCollection : ICollection {
542 private ICollection values;
543 private Array valueArray;
547 /// Initializes a new instance of the <see cref='System.ComponentModel.TypeConverter.StandardValuesCollection'/>
551 public StandardValuesCollection(ICollection values) {
552 if (values == null) {
553 values = new object[0];
556 Array a = values as Array;
561 this.values = values;
566 /// Gets the number of objects in the collection.
571 if (valueArray != null) {
572 return valueArray.Length;
581 /// <para>Gets the object at the specified index number.</para>
583 public object this[int index] {
585 if (valueArray != null) {
586 return valueArray.GetValue(index);
588 IList list = values as IList;
592 // No other choice but to enumerate the collection.
594 valueArray = new object[values.Count];
595 values.CopyTo(valueArray, 0);
596 return valueArray.GetValue(index);
601 /// <para>Copies the contents of this collection to an array.</para>
603 public void CopyTo(Array array, int index) {
604 values.CopyTo(array, index);
609 /// Gets an enumerator for this collection.
612 public IEnumerator GetEnumerator() {
613 return values.GetEnumerator();
618 /// Retrieves the count of objects in the collection.
620 int ICollection.Count {
628 /// Determines if this collection is synchronized.
629 /// The ValidatorCollection is not synchronized for
630 /// speed. Also, since it is read-only, there is
631 /// no need to synchronize it.
633 bool ICollection.IsSynchronized {
641 /// Retrieves the synchronization root for this
642 /// collection. Because we are not synchronized,
643 /// this returns null.
645 object ICollection.SyncRoot {
653 /// Copies the contents of this collection to an array.
655 void ICollection.CopyTo(Array array, int index) {
656 CopyTo(array, index);
661 /// Retrieves a new enumerator that can be used to
662 /// iterate over the values in this collection.
664 IEnumerator IEnumerable.GetEnumerator() {
665 return GetEnumerator();