2010-08-28 2 views
2

У меня есть перечисление, и я хочу «скрыть» одно из его значений (как добавить его для будущей поддержки). Код написан на C#.Значение enum как скрытое в C#

public enum MyEnum 
{ 
    ValueA = 0, 

    ValueB = 1, 

    Reserved 
} 

Я не хочу, чтобы люди, использующие этот код, использовали эти значения (MyEnum.Reserved). Любая идея? TIA

+0

Разработчики, которые используют мой код. Я хочу разрешить им только ValueA и ValueB – Tom

+3

Ну тогда вы не можете, разработчики похожи на мафию, ничего не скрывает :-) –

ответ

5

Если вы не хотите, чтобы показать его, то не включайте его:

public enum MyEnum 
{ 
    ValueA = 0, 
    ValueB = 1, 
} 

Обратите внимание, что пользователь данного перечисления еще может присвоить любое целое значение переменной, объявленной в MyEnum:

MyEnum e = (MyEnum)2; // works! 

Это означает, что метод, который принимает перечисление всегда должны проверить этот вход перед использованием:

void DoIt(MyEnum e) 
{ 
    if (e != MyEnum.ValueA && e != MyEnum.ValueB) 
    { 
     throw new ArgumentException(); 
    } 

    // ... 
} 

Таким образом, просто добавить значение позже, когда вам это нужно, d измените свои методы, чтобы принять его.

+0

В последнем примере вы можете использовать 'Enum.IsDefined' (http://msdn.microsoft.com/en-us/library/system.enum.isdefined.aspx). Это обычно было бы намного проще, чем проверять каждое значение, и оно также надежно для будущего (вы бы не хотели изменять метод, если новое значение добавлено в перечисление). –

+1

@ 0xA3: Руководства по дизайну Framework рекомендуют против этого: ** «НЕ используйте Enum.IsDefined для проверок диапазона перечислений». ** Одна из причин - производительность (Enum.IsDefined внутренне использует отражение и очень медленно); другая причина - это точно проблема с версией, при которой использование Enum.IsDefined делает ошибку кода подверженной при расширении перечисления. Лучше избегать Enum.IsDefined и делать проверки вручную. – dtb

2

Это невозможно в C#. Все значения перечисления доступны, если доступно Enum.

Единственный способ, которым вы могли бы имитировать это достижение, - использовать менее доступное статическое поле, в котором используется целочисленное значение, которое еще не используется в Enum.

public enum MyEnum { 
    ValueA = 0; 
    ValueB = 1; 
} 

internal static class MyEnumEx { 
    internal static MyEnum Reserved = (MyEnum)42; 
} 

Мне любопытно, но почему вы хотели бы это сделать. Независимо от того, что вы делаете, пользователи все равно могут предоставить значение Reserved. Все, что нужно сделать, - это присвоить int соответствующее значение для типа MyEnum.

// Code that shouldn't access Reserve 
MyEnum reserved = (MyEnum)42; // Woot! 
+0

Хороший всеобъемлющий ответ. –

0

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

2

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

// This type works pretty much the same way an enum works; 
// each specific value can be cast to/from an int, and each has 
// a specific name that is returned on calling ToString(). 
public sealed class MyEnum 
{ 
    private readonly int _value; 
    private readonly string _name; 

    // private constructor -- ensure that the static members you define below 
    // are the only MyEnum instances accessible from any outside code 
    private MyEnum(int value, string name) 
    { 
     _value = value; 
     _name = name; 
    } 

    // no need to override Equals or GetHashCode, believe it or not -- 
    // one instance per value means we can use reference equality and 
    // that should be just fine 
    public override string ToString() 
    { 
     return _name; 
    } 

    // provide direct access only to these members 
    public static readonly MyEnum ValueA = new MyEnum(0, "ValueA"); 
    public static readonly MyEnum ValueB = new MyEnum(1, "ValueB"); 

    // this member is only available to you within the current assembly 
    internal static readonly MyEnum Reserved = new MyEnum(-1, "Reserved"); 
} 

Вы могли бы еще больше эмулировать поведение enum значений, например, перегрузки explicit операторов для преобразования в/из MyEnum объектов к int ценностей (принял предложение JaredPar, чтобы использовать эту функцию, а не implicit):

public static explicit operator MyEnum(int value) 
{ 
    switch (value) 
    { 
     case 0: 
      return ValueA; 
     case 1: 
      return ValueB; 
     default: 
      throw new InvalidCastException(); 
    } 
} 

public static explicit operator int(MyEnum value) 
{ 
    return value._value; 
} 
+1

Тогда «плохие» разработчики могли просто сделать это. 'MyEnum reserved = -1;', и OP возвращается туда, где он начал. Кроме того, вам нужно переопределить операции равенства, чтобы получить семантику значений обратно – JaredPar

+0

@ JaredPar: Но перегрузка оператора 'implicit' и только принятие 0 или 1 специально исключали бы это, не так ли? Я также рассмотрел переопределение операций равенства, но на самом деле я не думаю, что это необходимо, так как существует только один экземпляр объекта MyEnum за значение (из-за частного конструктора и только определенных статических членов readonly), что означает, что эффективное равенство ссылок * становится равенством значения для этого типа. –

+0

ах я вижу, как ты подорвал этот трюк. Ницца. Было бы лучше, если бы это было явным или неявным, хотя это привело бы к тонким ошибкам во время выполнения. – JaredPar

8

Вы можете использовать «Устаревший атрибут» - семантически неправильный, но он будет делать то, что вы хотите:

public enum MyEnum 
{ 
    ValueA = 0, 
    ValueB = 1, 
    [Obsolete("Do not use this", true)] 
    Reserved 
} 

Любой, кто пытается собрать с помощью Foo.Reserved элемент получит ошибку

+0

Как взломать, мне очень нравится этот :-) –

0

ARE YOU используя внутреннее «скрытое» значение?В противном случае:

public enum MyEnum 
{ 
    ValueA = 0, 
    ValueB = 1, 
    //TODO: Reserved 
} 

Вы ничего не получаете путем определения неиспользуемой переменной.

0

, если вы хотите, чтобы скрыть от IntelliSense или PropertyGrid перечисленных членов, вы можете обратиться:

[System.ComponentModel.EditorBrowsable (System.ComponentModel.EditorBrowsableState.Never)]

и

[ System.ComponentModel.Browsable (ложь)]

Пример:

public enum MyEnum 
    { 
    A, 

    B, 
    [System.ComponentModel.Browsable(false)] 
    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] 
    C 
    } 

C не видно

0

В одну сторону вы можете установить значение этой переменной null. поэтому когда-либо его вызываемый от enum он будет b null. в короткий пользователь не может получить доступ к его значению.

public enum MyEnum 
{ 
    ValueA = 0, 
    ValueB = 1, 

    Reserved.None 
}