The Labs \ Source Viewer \ SSCLI \ System.ComponentModel \ EnumConverter

  1. //------------------------------------------------------------------------------
  2. // <copyright file="EnumConverter.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. /*
  16. */
  17. namespace System.ComponentModel
  18. {
  19.     using Microsoft.Win32;
  20.     using System.Collections;
  21.     using System.Collections.Generic;
  22.     using System.ComponentModel.Design.Serialization;
  23.     using System.Globalization;
  24.     using System.Diagnostics;
  25.     using System.Reflection;
  26.     using System.Runtime.Serialization.Formatters;
  27.     using System.Runtime.Remoting;
  28.     using System.Runtime.InteropServices;
  29.     using System.Security.Permissions;
  30.    
  31.     /// <devdoc>
  32.     /// <para>Provides a type converter to convert <see cref='System.Enum'/>
  33.     /// objects to and from various
  34.     /// other representations.</para>
  35.     /// </devdoc>
  36.     [HostProtection(SharedState = true)]
  37.     public class EnumConverter : TypeConverter
  38.     {
  39.         /// <devdoc>
  40.         /// <para>
  41.         /// Provides a <see cref='System.ComponentModel.TypeConverter.StandardValuesCollection'/> that specifies the
  42.         /// possible values for the enumeration.
  43.         /// </para>
  44.         /// </devdoc>
  45.         private StandardValuesCollection values;
  46.         /// <devdoc>
  47.         /// <para>
  48.         /// Specifies
  49.         /// the
  50.         /// type of the enumerator this converter is
  51.         /// associated with.
  52.         /// </para>
  53.         /// </devdoc>
  54.         private Type type;
  55.        
  56.         /// <devdoc>
  57.         /// <para>
  58.         /// Initializes a new instance of the <see cref='System.ComponentModel.EnumConverter'/> class for the given
  59.         /// type.
  60.         /// </para>
  61.         /// </devdoc>
  62.         public EnumConverter(Type type)
  63.         {
  64.             this.type = type;
  65.         }
  66.        
  67.         /// <devdoc>
  68.         /// <para>[To be supplied.]</para>
  69.         /// </devdoc>
  70.         protected Type EnumType {
  71.             get { return type; }
  72.         }
  73.        
  74.         /// <devdoc>
  75.         /// <para>[To be supplied.]</para>
  76.         /// </devdoc>
  77.         protected StandardValuesCollection Values {
  78.             get { return values; }
  79.             set { values = value; }
  80.         }
  81.        
  82.         /// <internalonly/>
  83.         /// <devdoc>
  84.         /// <para>Gets a value indicating whether this converter
  85.         /// can convert an object in the given source type to an enumeration object using
  86.         /// the specified context.</para>
  87.         /// </devdoc>
  88.         public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
  89.         {
  90.             if (sourceType == typeof(string) || sourceType == typeof(Enum[])) {
  91.                 return true;
  92.             }
  93.             return base.CanConvertFrom(context, sourceType);
  94.         }
  95.        
  96.         /// <devdoc>
  97.         /// <para>Gets a value indicating whether this converter can
  98.         /// convert an object to the given destination type using the context.</para>
  99.         /// </devdoc>
  100.         public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
  101.         {
  102.             if (destinationType == typeof(InstanceDescriptor) || destinationType == typeof(Enum[])) {
  103.                 return true;
  104.             }
  105.             return base.CanConvertTo(context, destinationType);
  106.         }
  107.        
  108.         /// <devdoc>
  109.         /// <para>Gets an <see cref='System.Collections.IComparer'/>
  110.         /// interface that can
  111.         /// be used to sort the values of the enumerator.</para>
  112.         /// </devdoc>
  113.         protected virtual IComparer Comparer {
  114.             get { return InvariantComparer.Default; }
  115.         }
  116.        
  117.         /// <internalonly/>
  118.         /// <devdoc>
  119.         /// <para>Converts the specified value object to an enumeration object.</para>
  120.         /// </devdoc>
  121.         public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
  122.         {
  123.             if (value is string) {
  124.                 try {
  125.                     string strValue = (string)value;
  126.                     if (strValue.IndexOf(',') != -1) {
  127.                         long convertedValue = 0;
  128.                         string[] values = strValue.Split(new char[] {','});
  129.                         foreach (string v in values) {
  130.                             convertedValue |= Convert.ToInt64((Enum)Enum.Parse(type, v, true), culture);
  131.                         }
  132.                         return Enum.ToObject(type, convertedValue);
  133.                     }
  134.                     else {
  135.                         return Enum.Parse(type, strValue, true);
  136.                     }
  137.                 }
  138.                 catch (Exception e) {
  139.                     throw new FormatException(SR.GetString(SR.ConvertInvalidPrimitive, (string)value, type.Name), e);
  140.                 }
  141.             }
  142.             else if (value is Enum[]) {
  143.                 long finalValue = 0;
  144.                 foreach (Enum e in (Enum[])value) {
  145.                     finalValue |= Convert.ToInt64(e, culture);
  146.                 }
  147.                 return Enum.ToObject(type, finalValue);
  148.             }
  149.             return base.ConvertFrom(context, culture, value);
  150.         }
  151.        
  152.         /// <internalonly/>
  153.         /// <devdoc>
  154.         /// <para>Converts the given
  155.         /// value object to the
  156.         /// specified destination type.</para>
  157.         /// </devdoc>
  158.         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1803:AvoidCostlyCallsWherePossible")]
  159.         // Keep call to Enum.IsDefined
  160.         public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
  161.         {
  162.             if (destinationType == null) {
  163.                 throw new ArgumentNullException("destinationType");
  164.             }
  165.            
  166.             if (destinationType == typeof(string) && value != null) {
  167.                 // Raise an argument exception if the value isn't defined and if
  168.                 // the enum isn't a flags style.
  169.                 //
  170.                 Type underlyingType = Enum.GetUnderlyingType(type);
  171.                 if (value is IConvertible && value.GetType() != underlyingType) {
  172.                     value = ((IConvertible)value).ToType(underlyingType, culture);
  173.                 }
  174.                 if (!type.IsDefined(typeof(FlagsAttribute), false) && !Enum.IsDefined(type, value)) {
  175.                     throw new ArgumentException(SR.GetString(SR.EnumConverterInvalidValue, value.ToString(), type.Name));
  176.                 }
  177.                
  178.                 return Enum.Format(type, value, "G");
  179.             }
  180.             if (destinationType == typeof(InstanceDescriptor) && value != null) {
  181.                 string enumName = ConvertToInvariantString(context, value);
  182.                
  183.                 if (type.IsDefined(typeof(FlagsAttribute), false) && enumName.IndexOf(',') != -1) {
  184.                     // This is a flags enum, and there is no one flag
  185.                     // that covers the value. Instead, convert the
  186.                     // value to the underlying type and invoke
  187.                     // a ToObject call on enum.
  188.                     //
  189.                     Type underlyingType = Enum.GetUnderlyingType(type);
  190.                     if (value is IConvertible) {
  191.                         object convertedValue = ((IConvertible)value).ToType(underlyingType, culture);
  192.                        
  193.                         MethodInfo method = typeof(Enum).GetMethod("ToObject", new Type[] {typeof(Type), underlyingType});
  194.                         if (method != null) {
  195.                             return new InstanceDescriptor(method, new object[] {type, convertedValue});
  196.                         }
  197.                     }
  198.                 }
  199.                 else {
  200.                     FieldInfo info = type.GetField(enumName);
  201.                     if (info != null) {
  202.                         return new InstanceDescriptor(info, null);
  203.                     }
  204.                 }
  205.             }
  206.             if (destinationType == typeof(Enum[]) && value != null) {
  207.                 if (type.IsDefined(typeof(FlagsAttribute), false)) {
  208.                     List<Enum> flagValues = new List<Enum>();
  209.                    
  210.                     Array objValues = Enum.GetValues(type);
  211.                     long[] ulValues = new long[objValues.Length];
  212.                     for (int idx = 0; idx < objValues.Length; idx++) {
  213.                         ulValues[idx] = Convert.ToInt64((Enum)objValues.GetValue(idx), culture);
  214.                     }
  215.                    
  216.                     long longValue = Convert.ToInt64((Enum)value, culture);
  217.                     bool valueFound = true;
  218.                     while (valueFound) {
  219.                         valueFound = false;
  220.                         foreach (long ul in ulValues) {
  221.                             if ((ul != 0 && (ul & longValue) == ul) || ul == longValue) {
  222.                                 flagValues.Add((Enum)Enum.ToObject(type, ul));
  223.                                 valueFound = true;
  224.                                 longValue &= ~ul;
  225.                                 break;
  226.                             }
  227.                         }
  228.                        
  229.                         if (longValue == 0) {
  230.                             break;
  231.                         }
  232.                     }
  233.                    
  234.                     if (!valueFound && longValue != 0) {
  235.                         flagValues.Add((Enum)Enum.ToObject(type, longValue));
  236.                     }
  237.                    
  238.                     return flagValues.ToArray();
  239.                 }
  240.                 else {
  241.                     return new Enum[] {(Enum)Enum.ToObject(type, value)};
  242.                 }
  243.             }
  244.            
  245.             return base.ConvertTo(context, culture, value, destinationType);
  246.         }
  247.        
  248.         /// <internalonly/>
  249.         /// <devdoc>
  250.         /// <para>Gets a collection of standard values for the data type this validator is
  251.         /// designed for.</para>
  252.         /// </devdoc>
  253.         public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
  254.         {
  255.             if (values == null) {
  256.                 // We need to get the enum values in this rather round-about way so we can filter
  257.                 // out fields marked Browsable(false). Note that if multiple fields have the same value,
  258.                 // the behavior is undefined, since what we return are just enum values, not names.
  259.                
  260.                 Type reflectType = TypeDescriptor.GetReflectionType(type);
  261.                 if (reflectType == null) {
  262.                     reflectType = type;
  263.                 }
  264.                
  265.                 FieldInfo[] fields = reflectType.GetFields(BindingFlags.Public | BindingFlags.Static);
  266.                 ArrayList objValues = null;
  267.                
  268.                 if (fields != null && fields.Length > 0) {
  269.                     objValues = new ArrayList(fields.Length);
  270.                 }
  271.                
  272.                 if (objValues != null) {
  273.                     foreach (FieldInfo field in fields) {
  274.                         BrowsableAttribute browsableAttr = null;
  275.                         foreach (Attribute attr in field.GetCustomAttributes(typeof(BrowsableAttribute), false)) {
  276.                             browsableAttr = attr as BrowsableAttribute;
  277.                         }
  278.                        
  279.                         if (browsableAttr == null || browsableAttr.Browsable) {
  280.                             object value = null;
  281.                            
  282.                             try {
  283.                                 if (field.Name != null) {
  284.                                     value = Enum.Parse(type, field.Name);
  285.                                 }
  286.                             }
  287.                             catch (ArgumentException) {
  288.                                 // Hmm, for some reason, the parse threw. Let us ignore this value.
  289.                             }
  290.                            
  291.                             if (value != null) {
  292.                                 objValues.Add(value);
  293.                             }
  294.                         }
  295.                     }
  296.                    
  297.                     IComparer comparer = Comparer;
  298.                     if (comparer != null) {
  299.                         objValues.Sort(comparer);
  300.                     }
  301.                 }
  302.                
  303.                 Array arr = (objValues != null) ? objValues.ToArray() : null;
  304.                 values = new StandardValuesCollection(arr);
  305.             }
  306.             return values;
  307.         }
  308.        
  309.         /// <internalonly/>
  310.         /// <devdoc>
  311.         /// <para>Gets a value indicating whether the list of standard values returned from
  312.         /// <see cref='System.ComponentModel.TypeConverter.GetStandardValues'/>
  313.         /// is an exclusive list using the specified context.</para>
  314.         /// </devdoc>
  315.         public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
  316.         {
  317.             return !type.IsDefined(typeof(FlagsAttribute), false);
  318.         }
  319.        
  320.         /// <internalonly/>
  321.         /// <devdoc>
  322.         /// <para>Gets a value indicating
  323.         /// whether this object
  324.         /// supports a standard set of values that can be picked
  325.         /// from a list using the specified context.</para>
  326.         /// </devdoc>
  327.         public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
  328.         {
  329.             return true;
  330.         }
  331.        
  332.         /// <internalonly/>
  333.         /// <devdoc>
  334.         /// <para>Gets a value indicating whether the given object value is valid for this type.</para>
  335.         /// </devdoc>
  336.         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1803:AvoidCostlyCallsWherePossible")]
  337.         // Keep call to Enum.IsDefined
  338.         public override bool IsValid(ITypeDescriptorContext context, object value)
  339.         {
  340.             return Enum.IsDefined(type, value);
  341.         }
  342.     }
  343. }

Developer Fusion