2009-06-29 3 views
55

У меня есть очень большой набор разрешений в моем приложении, который я представляю с перечислением Flags. Он быстро приближается к практической верхней границе длинного типа данных. И я вынужден в ближайшее время разработать стратегию перехода к другой структуре. Теперь я могу разбить этот список на более мелкие части, однако это уже просто подмножество общих разрешений для нашего приложения на основе нашего макета приложений. Мы используем это различие широко для отображения при управлении разрешениями, и я бы предпочел не пересматривать этот код в это время, если я могу его избежать.Что делать, когда бит-маска (флаги) переполняется слишком большим

Спрашивает ли кто-нибудь еще этот вопрос? Как вы прошли мимо него? Общие примеры в порядке, но меня больше всего интересует конкретный пример C#, если есть какие-либо специфические для языка трюки, которые я могу использовать для выполнения работы.

Возможно, это не обязательно, но вот список разрешений, определенных в настоящее время для части приложения, с которым я имею дело.

//Subgroup WebAgent 
[Flags] 
public enum WebAgentPermission : long 
{ 
    [DescriptionAttribute("View Rule Group")] 
    ViewRuleGroup = 1, 
    [DescriptionAttribute("Add Rule Group")] 
    AddRuleGroup = 2, 
    [DescriptionAttribute("Edit Rule Group")] 
    EditRuleGroup = 4, 
    [DescriptionAttribute("Delete Rule Group")] 
    DeleteRuleGroup = 8, 
    [DescriptionAttribute("View Rule")] 
    ViewRule = 16, 
    [DescriptionAttribute("Add Rule")] 
    AddRule = 32, 
    [DescriptionAttribute("Edit Rule")] 
    EditRule = 64, 
    [DescriptionAttribute("Delete Rule")] 
    DeleteRule = 128, 
    [DescriptionAttribute("View Location")] 
    ViewLocation = 256, 
    [DescriptionAttribute("Add Location")] 
    AddLocation = 512, 
    [DescriptionAttribute("Edit Location")] 
    EditLocation = 1024, 
    [DescriptionAttribute("Delete Location")] 
    DeleteLocation = 2048, 
    [DescriptionAttribute("View Volume Statistics")] 
    ViewVolumeStatistics = 4096, 
    [DescriptionAttribute("Edit Volume Statistics")] 
    EditVolumeStatistics = 8192, 
    [DescriptionAttribute("Upload Volume Statistics")] 
    UploadVolumeStatistics = 16384, 
    [DescriptionAttribute("View Role")] 
    ViewRole = 32768, 
    [DescriptionAttribute("Add Role")] 
    AddRole = 65536, 
    [DescriptionAttribute("Edit Role")] 
    EditRole = 131072, 
    [DescriptionAttribute("Delete Role")] 
    DeleteRole = 262144, 
    [DescriptionAttribute("View User")] 
    ViewUser = 524288, 
    [DescriptionAttribute("Add User")] 
    AddUser = 1048576, 
    [DescriptionAttribute("Edit User")] 
    EditUser = 2097152, 
    [DescriptionAttribute("Delete User")] 
    DeleteUser = 4194304, 
    [DescriptionAttribute("Assign Permissions To User")] 
    AssignPermissionsToUser = 8388608, 
    [DescriptionAttribute("Change User Password")] 
    ChangeUserPassword = 16777216, 
    [DescriptionAttribute("View Audit Logs")] 
    ViewAuditLogs = 33554432, 
    [DescriptionAttribute("View Team")] 
    ViewTeam = 67108864, 
    [DescriptionAttribute("Add Team")] 
    AddTeam = 134217728, 
    [DescriptionAttribute("Edit Team")] 
    EditTeam = 268435456, 
    [DescriptionAttribute("Delete Team")] 
    DeleteTeam = 536870912, 
    [DescriptionAttribute("View Web Agent Reports")] 
    ViewWebAgentReports = 1073741824, 
    [DescriptionAttribute("View All Locations")] 
    ViewAllLocations = 2147483648, 
    [DescriptionAttribute("Access to My Search")] 
    AccessToMySearch = 4294967296, 
    [DescriptionAttribute("Access to Pespective Search")] 
    AccessToPespectiveSearch = 8589934592, 
    [DescriptionAttribute("Add Pespective Search")] 
    AddPespectiveSearch = 17179869184, 
    [DescriptionAttribute("Edit Pespective Search")] 
    EditPespectiveSearch = 34359738368, 
    [DescriptionAttribute("Delete Pespective Search")] 
    DeletePespectiveSearch = 68719476736, 
    [DescriptionAttribute("Access to Search")] 
    AccessToSearch = 137438953472, 
    [DescriptionAttribute("View Form Roles")] 
    ViewFormRole = 274877906944, 
    [DescriptionAttribute("Add/Edit Form Roles")] 
    AddFormRole = 549755813888, 
    [DescriptionAttribute("Delete UserFormRolesDifferenceMasks")] 
    DeleteFormRole = 1099511627776, 
    [DescriptionAttribute("Export Locations")] 
    ExportLocations = 2199023255552, 
    [DescriptionAttribute("Import Locations")] 
    ImportLocations = 4398046511104, 
    [DescriptionAttribute("Manage Location Levels")] 
    ManageLocationLevels = 8796093022208, 
    [DescriptionAttribute("View Job Title")] 
    ViewJobTitle = 17592186044416, 
    [DescriptionAttribute("Add Job Title")] 
    AddJobTitle = 35184372088832, 
    [DescriptionAttribute("Edit Job Title")] 
    EditJobTitle = 70368744177664, 
    [DescriptionAttribute("Delete Job Title")] 
    DeleteJobTitle = 140737488355328, 
    [DescriptionAttribute("View Dictionary Manager")] 
    ViewDictionaryManager = 281474976710656, 
    [DescriptionAttribute("Add Dictionary Manager")] 
    AddDictionaryManager = 562949953421312, 
    [DescriptionAttribute("Edit Dictionary Manager")] 
    EditDictionaryManager = 1125899906842624, 
    [DescriptionAttribute("Delete Dictionary Manager")] 
    DeleteDictionaryManager = 2251799813685248, 
    [DescriptionAttribute("View Choice Manager")] 
    ViewChoiceManager = 4503599627370496, 
    [DescriptionAttribute("Add Choice Manager")] 
    AddChoiceManager = 9007199254740992, 
    [DescriptionAttribute("Edit Chioce Manager")] 
    EditChoiceManager = 18014398509481984, 
    [DescriptionAttribute("Delete Choice Manager")] 
    DeleteChoiceManager = 36028797018963968, 
    [DescriptionAttribute("Import Export Choices")] //57 
    ImportExportChoices = 72057594037927936 
} 
+53

Для ясности я обычно использую: (1 << 0), (1 << 1), .. (1 << 57) для моих флагов. Легче понять и усложнить ошибку. Однако на ваш вопрос не отвечает. – Talljoe

+0

Спасибо, я попробовал несколько способов сделать что-то подобное, но я всегда получаю не могу использовать вычисленное значение для ошибки перечислений. –

+0

Действительно? Можете ли вы показать пример? Должно быть законным использовать рассчитанные значения в инициализации для члена перечисления, если это не вызывает циклов в цепочке зависимостей. –

ответ

29

Я вижу значения, по меньшей мере, нескольких различных перечислений в там ...

Моя первая мысль была подойти к решению проблемы путем разделения прав доступа в логические группы (RuleGroupPermissions, RulePermissions, LocationPermissions, ...), а затем с классом (WebAgentPermissions), отображающим свойство для каждого типа перечисления разрешений.

Поскольку значения разрешения кажутся повторяющимися, вы, вероятно, может уйти с одного перечисления в конце:

[Flags] 
public enum Permissions 
{ 
    View = 1, 
    Add = 2, 
    Edit = 4, 
    Delete = 8 
} 

И тогда есть WebAgentPermissions класс выставить свойство для каждой области, где разрешения должен быть установлен;

class WebAgentPermissions 
{ 
    public Permissions RuleGroup { get; set; } 
    public Permissions Rule{ get; set; } 
    public Permissions Location{ get; set; } 
    // and so on... 
} 
+2

Мне это нравится, и пока они довольно стандартны, я думаю, что есть достаточно отклонений, чтобы сделать это решение несколько громоздким , В конце концов, я думаю, что мне просто нужно сосать его и сломать этого зверя на мелкие кусочки, а также обработать несколько разделов моего приложения, чтобы обработать изменения. Я просто надеялся, что там была волшебная пуля, которую я не нашел. Спасибо за ваше время. –

+1

Это довольно хорошее решение в этом случае. К сожалению, это не дает общий способ справиться с подобными проблемами, кроме «попытаться разбить его на лучшее значение перечисления». – PPC

12

Язык документация говорит:

http://msdn.microsoft.com/en-us/library/system.flagsattribute.aspx

«Основной тип Int32 и поэтому максимальный один бит флаг 1073741824 и, очевидно, есть в общей сложности 32 флагов для каждого перечисления.»

Однако ... ОБНОВЛЕНО:

Commenter правильно. Проверьте это:

http://msdn.microsoft.com/en-us/library/ms182147(VS.80).aspx

Int32 лишь DEFAULT тип данных! Фактически вы можете указать Int64.

public enum MyEnumType : Int64 

... допускается до 64 значений. Но это, безусловно, кажется максимальным, после этого вы будете смотреть на реинжиниринг. Не зная слишком много о остальном вашем решении, я не могу точно сказать, что может подойти. Но массив (или хэш-карта) идентификаторов привилегий, вероятно, является наиболее естественным подходом.

+0

цитата, которую вы отправили, от комментатора, и я считаю, что он неверен. Атрибут Flag вообще не указывает информацию о типе. Хотя перечисления являются Int32 по умолчанию, если вы явно не указываете тип. –

+4

+1, 64 разрешений должно быть достаточно для кого-то ... –

+4

@PatrickM к сожалению, в то время как это отличный анекдот, это не реальность, и мне нужно больше. – leigero

4

В C#, один гибкий способ для представления значения, которое вроде перечисления, но более гибко, чтобы представить его в качестве статического класса с термообработанными значениями доступны, как это:

public sealed class WebAgentPermission 
{ 
    private long ID; 

    public static readonly WebAgentPermission 
     ViewRuleGroup = new WebAgentPermission { ID = 1 }; 
    public static readonly WebAgentPermission 
     AddRuleGroup = new WebAgentPermission { ID = 2 }; 

    private WebAgentPermission() { } 

    // considerations: override equals/gethashcode, probably override tostring, 
    // maybe implicit cast to/from long, maybe other stuff 
} 

В качестве альтернативы, только раскол дело вверх; похоже, вы могли бы, если бы вы действительно пробовали.

+0

Это достойный способ взглянуть на эту проблему, а не на то, что я рассматривал до сих пор. Спасибо за ваш вклад. –

1

Я не был в этой ситуации.

Вот что я думаю, создайте отдельные перечисления для каждой категории & признайте их как параметры.

RuleGroupPermission 
    None = 0 
    ViewRuleGroup = 1, 
    AddRuleGroup = 2, 
    EditRuleGroup = 4, 
    DeleteRuleGroup = 8, 

LocationOperations 
    None = 0 
    Add = 1 
    View = 2 
    Delete = 4 

void setPermission(RuleGroupPermission ruleGroupOpsAllowed, LocationOperations locationOptions) 
{ 
    ... 
} 

EDIT: Посмотрите, как это делает messagebox.show. OK, OKCancel отделены от вопроса, информации, восклицания.

4

Если бы я контролировал это приложение, я бы, вероятно, придумал общий набор разрешений (просмотр, добавление, изменение, удаление, загрузка/импорт) и набор ресурсов (пользователи, роли, правила и т. Д.).). На веб-странице найдите тип ресурса, связанный с этой страницей, а затем проверьте разрешения. Возможно, что-то вроде:

Permissions perms = agent.GetPermissions(ResourceType.User); 
if((perms & Permissions.View) == Permissions.View) { /* do work */ } 

или

Permissions perms = agent.Permissions[ResourceType.User]; 
if((perms & Permissions.View) == Permissions.View) { /* do work */ } 

или даже

if(agent.IsAuthorized(ResourceType.User, Permissions.View)) { /* do work */ } 

У вас есть несколько разрешений, которые не имеют смысла и все остальное (Назначают Permissoins пользователю, чтобы имя один). Я не уверен, как бы я справился с этим, основываясь на том, как мало я знаю проблему.

+0

+1 для вашего комментария выше, если ничего другого, спасибо за ваше время. –

11

Вы можете проверить класс BitArray. Возможно, вы будете использовать его в будущем.

+0

Это хороший вариант, но, конечно же, вы должны инкапсулировать его в класс, который дает имена всем этим битам, как предлагали другие плакаты. –

+0

Класс BitArray идеален - определить класс с публичным перечислением для разрешений (только последовательные целые числа, начинающиеся с 0), и иметь функцию запроса, которая просто возвращает значения частного элемента BitArray, проиндексированного перечислением разрешений). Это позволит эффективно обрабатывать произвольное количество разрешений. –

+0

Ницца. И это поддерживается в 1.0. – HelloSam

4

Это оказалось более распространенной проблемой, чем я думал, это было бы, где я представлял классы CSS как типы флагов и было более 64 возможностей. Я взял все, что я узнал из этого процесса, и превратил его в шаблон многократного использования, хотя, так как это структура, это шаблон типа «копирование и вставка».

Это BigFlags «перечисленный тип». Он использует либо BigInteger от System.Numerics, либо если вы не можете ссылаться на эту сборку, есть резерв, который использует BitArray, просто отключив предпроцессорную директиву NUMERICS.

Он ведет себя замечательно, как Flags перечислимые, даже определяя такие вещи, как HasFlag(...), GetNames(), GetValues(), TryParse(...), TypeConverter, IConvertible и т.д. Так как это делает определит TypeConverter и IConvertible, он также подходит для хранения в хранилище данных , хотя всегда в виде строкового или текстового типа данных.

Вы публикуете значения «enum» как public static readonly. Комбинированные значения перечисления отображаются как свойства только для получения.

Чтобы использовать его, скопируйте и вставьте код, затем выполните поиск и замените на BigFlags с вашим именем структуры, затем удалите перечисления в разделе TODO и добавьте свои значения.

Надеюсь, что кто-то посчитает это полезным.

#define NUMERICS 

using System; 
using System.Collections; 
using System.Collections.Concurrent; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Globalization; 
using System.Linq; 
#if NUMERICS 
using System.Numerics; 
#endif 
using System.Reflection; 
using System.Text; 
using System.Threading.Tasks; 


namespace Aim 
{ 
    /// <summary> 
    /// The BigFlags struct behaves like a Flags enumerated type. 
    /// <para> 
    /// Note that if this struct will be stored in some type of data 
    /// store, it should be stored as a string type. There are two 
    /// reasons for this: 
    /// </para> 
    /// <para> 
    /// 1. Presumably, this pattern is being used because the number 
    /// of values will exceed 64 (max positions in a long flags enum). 
    /// Since this is so, there is in any case no numeric type which 
    /// can store all the possible combinations of flags. 
    /// </para> 
    /// <para> 
    /// 2. The "enum" values are assigned based on the order that the 
    /// static public fields are defined. It is much safer to store 
    /// these fields by name in case the fields are rearranged. This 
    /// is particularly important if this represents a permission set! 
    /// </para> 
    /// </summary> 
    [ 
    TypeConverter(typeof(BigFlagsConverter)) 
    ] 
    public struct BigFlags : IEquatable<BigFlags>, 
     IComparable<BigFlags>, IComparable, IConvertible 
    { 
     #region State... 

     private static readonly List<FieldInfo> Fields; 
     private static readonly List<BigFlags> FieldValues; 
#if NUMERICS 
     private static readonly bool ZeroInit = true; 
     private BigInteger Value; 

     /// <summary> 
     /// Creates a value taking ZeroInit into consideration. 
     /// </summary> 
     /// <param name="index"></param> 
     /// <returns></returns> 
     private static BigInteger CreateValue(int index) 
     { 
      if(ZeroInit && index == 0) 
      { 
       return 0; 
      } 
      int idx = ZeroInit ? index - 1 : index; 

      return new BigInteger(1) << idx; 
     } 
#else 
     private BitArray Array; 

     /// <summary> 
     /// Lazy-initialized BitArray. 
     /// </summary> 
     private BitArray Bits 
     { 
      get 
      { 
       if(null == Array) 
       { 
        Array = new BitArray(Fields.Count); 
       } 
       return Array; 
      } 
     } 
#endif 
     #endregion ...State 

     #region Construction... 

     /// <summary> 
     /// Static constructor. Sets the static public fields. 
     /// </summary> 
     static BigFlags() 
     { 
      Fields = typeof(BigFlags).GetFields(
       BindingFlags.Public | BindingFlags.Static).ToList(); 
      FieldValues = new List<BigFlags>(); 
      for(int i = 0; i < Fields.Count; i++) 
      { 
       var field = Fields[i]; 
       var fieldVal = new BigFlags(); 
#if NUMERICS 
       fieldVal.Value = CreateValue(i); 
#else 
       fieldVal.Bits.Set(i, true); 
#endif 
       field.SetValue(null, fieldVal); 
       FieldValues.Add(fieldVal); 
      } 
     } 
     #endregion ...Construction 

     #region Operators... 

     /// <summary> 
     /// OR operator. Or together BigFlags instances. 
     /// </summary> 
     /// <param name="lhs"></param> 
     /// <param name="rhs"></param> 
     /// <returns></returns> 
     public static BigFlags operator |(BigFlags lhs, BigFlags rhs) 
     { 
      var result = new BigFlags(); 
#if NUMERICS 
      result.Value = lhs.Value | rhs.Value; 
#else 
      // BitArray is modified in place - always copy! 
      result.Array = new BitArray(lhs.Bits).Or(rhs.Bits); 
#endif 

      return result; 
     } 

     /// <summary> 
     /// AND operator. And together BigFlags instances. 
     /// </summary> 
     /// <param name="lhs"></param> 
     /// <param name="rhs"></param> 
     /// <returns></returns> 
     public static BigFlags operator &(BigFlags lhs, BigFlags rhs) 
     { 
      var result = new BigFlags(); 
#if NUMERICS 
      result.Value = lhs.Value & rhs.Value; 
#else 
      // BitArray is modified in place - always copy! 
      result.Array = new BitArray(lhs.Bits).And(rhs.Bits); 
#endif 

      return result; 
     } 

     /// <summary> 
     /// XOR operator. Xor together BigFlags instances. 
     /// </summary> 
     /// <param name="lhs"></param> 
     /// <param name="rhs"></param> 
     /// <returns></returns> 
     public static BigFlags operator ^(BigFlags lhs, BigFlags rhs) 
     { 
      var result = new BigFlags(); 
#if NUMERICS 
      result.Value = lhs.Value^rhs.Value; 
#else 
      // BitArray is modified in place - always copy! 
      result.Array = new BitArray(lhs.Bits).Xor(rhs.Bits); 
#endif 

      return result; 
     } 

     /// <summary> 
     /// Equality operator. 
     /// </summary> 
     /// <param name="lhs"></param> 
     /// <param name="rhs"></param> 
     /// <returns></returns> 
     public static bool operator ==(BigFlags lhs, BigFlags rhs) 
     { 
      return lhs.Equals(rhs); 
     } 

     /// <summary> 
     /// Inequality operator. 
     /// </summary> 
     /// <param name="lhs"></param> 
     /// <param name="rhs"></param> 
     /// <returns></returns> 
     public static bool operator !=(BigFlags lhs, BigFlags rhs) 
     { 
      return !(lhs == rhs); 
     } 
     #endregion ...Operators 

     #region System.Object Overrides... 

     /// <summary> 
     /// Overridden. Returns a comma-separated string. 
     /// </summary> 
     /// <returns></returns> 
     public override string ToString() 
     { 
#if NUMERICS 
      if(ZeroInit && Value == 0) 
      { 
       return Fields[0].Name; 
      } 
#endif 
      var names = new List<string>(); 
      for(int i = 0; i < Fields.Count; i++) 
      { 
#if NUMERICS 
       if(ZeroInit && i == 0) 
        continue; 

       var bi = CreateValue(i); 
       if((Value & bi) == bi) 
        names.Add(Fields[i].Name); 
#else 
       if(Bits[i]) 
        names.Add(Fields[i].Name); 
#endif 
      } 

      return String.Join(", ", names); 
     } 

     /// <summary> 
     /// Overridden. Compares equality with another object. 
     /// </summary> 
     /// <param name="obj"></param> 
     /// <returns></returns> 
     public override bool Equals(object obj) 
     { 
      if(obj is BigFlags) 
      { 
       return Equals((BigFlags)obj); 
      } 

      return false; 
     } 

     /// <summary> 
     /// Overridden. Gets the hash code of the internal BitArray. 
     /// </summary> 
     /// <returns></returns> 
     public override int GetHashCode() 
     { 
#if NUMERICS 
      return Value.GetHashCode(); 
#else 
      int hash = 17; 
      for(int i = 0; i < Bits.Length; i++) 
      { 
       if(Bits[i]) 
        hash ^= i; 
      } 

      return hash; 
#endif 
     } 
     #endregion ...System.Object Overrides 

     #region IEquatable<BigFlags> Members... 

     /// <summary> 
     /// Strongly-typed equality method. 
     /// </summary> 
     /// <param name="other"></param> 
     /// <returns></returns> 
     public bool Equals(BigFlags other) 
     { 
#if NUMERICS 
      return Value == other.Value; 
#else 
      for(int i = 0; i < Bits.Length; i++) 
      { 
       if(Bits[i] != other.Bits[i]) 
        return false; 
      } 

      return true; 
#endif 
     } 
     #endregion ...IEquatable<BigFlags> Members 

     #region IComparable<BigFlags> Members... 

     /// <summary> 
     /// Compares based on highest bit set. Instance with higher 
     /// bit set is bigger. 
     /// </summary> 
     /// <param name="other"></param> 
     /// <returns></returns> 
     public int CompareTo(BigFlags other) 
     { 
#if NUMERICS 
      return Value.CompareTo(other.Value); 
#else 
      for(int i = Bits.Length - 1; i >= 0; i--) 
      { 
       bool thisVal = Bits[i]; 
       bool otherVal = other.Bits[i]; 
       if(thisVal && !otherVal) 
        return 1; 
       else if(!thisVal && otherVal) 
        return -1; 
      } 

      return 0; 
#endif 
     } 
     #endregion ...IComparable<BigFlags> Members 

     #region IComparable Members... 

     int IComparable.CompareTo(object obj) 
     { 
      if(obj is BigFlags) 
      { 
       return CompareTo((BigFlags)obj); 
      } 

      return -1; 
     } 
     #endregion ...IComparable Members 

     #region IConvertible Members... 

     /// <summary> 
     /// Returns TypeCode.Object. 
     /// </summary> 
     /// <returns></returns> 
     public TypeCode GetTypeCode() 
     { 
      return TypeCode.Object; 
     } 

     bool IConvertible.ToBoolean(IFormatProvider provider) 
     { 
      throw new NotSupportedException(); 
     } 

     byte IConvertible.ToByte(IFormatProvider provider) 
     { 
#if NUMERICS 
      return Convert.ToByte(Value); 
#else 
      throw new NotSupportedException(); 
#endif 
     } 

     char IConvertible.ToChar(IFormatProvider provider) 
     { 
      throw new NotSupportedException(); 
     } 

     DateTime IConvertible.ToDateTime(IFormatProvider provider) 
     { 
      throw new NotSupportedException(); 
     } 

     decimal IConvertible.ToDecimal(IFormatProvider provider) 
     { 
#if NUMERICS 
      return Convert.ToDecimal(Value); 
#else 
      throw new NotSupportedException(); 
#endif 
     } 

     double IConvertible.ToDouble(IFormatProvider provider) 
     { 
#if NUMERICS 
      return Convert.ToDouble(Value); 
#else 
      throw new NotSupportedException(); 
#endif 
     } 

     short IConvertible.ToInt16(IFormatProvider provider) 
     { 
#if NUMERICS 
      return Convert.ToInt16(Value); 
#else 
      throw new NotSupportedException(); 
#endif 
     } 

     int IConvertible.ToInt32(IFormatProvider provider) 
     { 
#if NUMERICS 
      return Convert.ToInt32(Value); 
#else 
      throw new NotSupportedException(); 
#endif 
     } 

     long IConvertible.ToInt64(IFormatProvider provider) 
     { 
#if NUMERICS 
      return Convert.ToInt64(Value); 
#else 
      throw new NotSupportedException(); 
#endif 
     } 

     sbyte IConvertible.ToSByte(IFormatProvider provider) 
     { 
#if NUMERICS 
      return Convert.ToSByte(Value); 
#else 
      throw new NotSupportedException(); 
#endif 
     } 

     float IConvertible.ToSingle(IFormatProvider provider) 
     { 
#if NUMERICS 
      return Convert.ToSingle(Value); 
#else 
      throw new NotSupportedException(); 
#endif 
     } 

     string IConvertible.ToString(IFormatProvider provider) 
     { 
      return ToString(); 
     } 

     object IConvertible.ToType(Type conversionType, IFormatProvider provider) 
     { 
      var tc = TypeDescriptor.GetConverter(this); 

      return tc.ConvertTo(this, conversionType); 
     } 

     ushort IConvertible.ToUInt16(IFormatProvider provider) 
     { 
#if NUMERICS 
      return Convert.ToUInt16(Value); 
#else 
      throw new NotSupportedException(); 
#endif 
     } 

     uint IConvertible.ToUInt32(IFormatProvider provider) 
     { 
#if NUMERICS 
      return Convert.ToUInt32(Value); 
#else 
      throw new NotSupportedException(); 
#endif 
     } 

     ulong IConvertible.ToUInt64(IFormatProvider provider) 
     { 
#if NUMERICS 
      return Convert.ToUInt64(Value); 
#else 
      throw new NotSupportedException(); 
#endif 
     } 
     #endregion ...IConvertible Members 

     #region Public Interface... 

     /// <summary> 
     /// Checks <paramref name="flags"/> to see if all the bits set in 
     /// that flags are also set in this flags. 
     /// </summary> 
     /// <param name="flags"></param> 
     /// <returns></returns> 
     public bool HasFlag(BigFlags flags) 
     { 
      return (this & flags) == flags; 
     } 

     /// <summary> 
     /// Gets the names of this BigFlags enumerated type. 
     /// </summary> 
     /// <returns></returns> 
     public static string[] GetNames() 
     { 
      return Fields.Select(x => x.Name).ToArray(); 
     } 

     /// <summary> 
     /// Gets all the values of this BigFlags enumerated type. 
     /// </summary> 
     /// <returns></returns> 
     public static BigFlags[] GetValues() 
     { 
      return FieldValues.ToArray(); 
     } 

     /// <summary> 
     /// Standard TryParse pattern. Parses a BigFlags result from a string. 
     /// </summary> 
     /// <param name="s"></param> 
     /// <param name="result"></param> 
     /// <returns></returns> 
     public static bool TryParse(string s, out BigFlags result) 
     { 
      result = new BigFlags(); 
      if(String.IsNullOrEmpty(s)) 
       return true; 

      var fieldNames = s.Split(','); 
      foreach(var f in fieldNames) 
      { 
       var field = Fields.FirstOrDefault(x => 
        String.Equals(x.Name, f.Trim(), 
        StringComparison.OrdinalIgnoreCase)); 
       if(null == field) 
       { 
        result = new BigFlags(); 
        return false; 
       } 
#if NUMERICS 
       int i = Fields.IndexOf(field); 
       result.Value |= CreateValue(i); 
#else 
       result.Bits.Set(Fields.IndexOf(field), true); 
#endif 
      } 

      return true; 
     } 

     // 
     // Expose "enums" as public static readonly fields. 
     // TODO: Replace this section with your "enum" values. 
     // 
     public static readonly BigFlags None; 
     public static readonly BigFlags FirstValue; 
     public static readonly BigFlags ValueTwo; 
     public static readonly BigFlags ValueThree; 
     public static readonly BigFlags ValueFour; 
     public static readonly BigFlags ValueFive; 
     public static readonly BigFlags ValueSix; 
     public static readonly BigFlags LastValue; 

     /// <summary> 
     /// Expose flagged combinations as get-only properties. 
     /// </summary> 
     public static BigFlags FirstLast 
     { 
      get 
      { 
       return BigFlags.FirstValue | BigFlags.LastValue; 
      } 
     } 
     #endregion ...Public Interface 
    } 

    /// <summary> 
    /// Converts objects to and from BigFlags instances. 
    /// </summary> 
    public class BigFlagsConverter : TypeConverter 
    { 
     /// <summary> 
     /// Can convert to string only. 
     /// </summary> 
     /// <param name="context"></param> 
     /// <param name="destinationType"></param> 
     /// <returns></returns> 
     public override bool CanConvertTo(ITypeDescriptorContext context, 
      Type destinationType) 
     { 
      return destinationType == typeof(String); 
     } 

     /// <summary> 
     /// Can convert from any object. 
     /// </summary> 
     /// <param name="context"></param> 
     /// <param name="sourceType"></param> 
     /// <returns></returns> 
     public override bool CanConvertFrom(ITypeDescriptorContext context, 
      Type sourceType) 
     { 
      return true; 
     } 

     /// <summary> 
     /// Converts BigFlags to a string. 
     /// </summary> 
     /// <param name="context"></param> 
     /// <param name="culture"></param> 
     /// <param name="value"></param> 
     /// <param name="destinationType"></param> 
     /// <returns></returns> 
     public override object ConvertTo(ITypeDescriptorContext context, 
      CultureInfo culture, object value, Type destinationType) 
     { 
      if(value is BigFlags && CanConvertTo(destinationType)) 
       return value.ToString(); 

      return null; 
     } 

     /// <summary> 
     /// Attempts to parse <paramref name="value"/> and create and 
     /// return a new BigFlags instance. 
     /// </summary> 
     /// <param name="context"></param> 
     /// <param name="culture"></param> 
     /// <param name="value"></param> 
     /// <returns></returns> 
     public override object ConvertFrom(ITypeDescriptorContext context, 
      CultureInfo culture, object value) 
     { 
      var s = Convert.ToString(value); 
      BigFlags result; 
      BigFlags.TryParse(s, out result); 

      return result; 
     } 
    } 
} 
Смежные вопросы