Подтвердить что ты не робот

Могу ли я избежать использования значения перечисления при попытке использовать или вернуть его?

Если у меня есть следующее перечисление:

public enum ReturnValue{
    Success = 0,
    FailReason1 = 1,
    FailReason2 = 2
    //Etc...
}

Могу ли я избежать кастинга, когда вернусь, например:

public static int main(string[] args){
    return (int)ReturnValue.Success;
}

Если нет, то почему по умолчанию значение enum не рассматривается как int?

4b9b3361

Ответ 1

перечисления должны быть безопасными по типу. Я думаю, что они не делали их неявно литыми, чтобы препятствовать другим видам использования. Хотя структура позволяет вам присваивать им постоянное значение, вы должны пересмотреть свои намерения. Если вы в основном используете перечисление для хранения постоянных значений, рассмотрите использование статического класса:

public static class ReturnValue
{
    public const int Success = 0;
    public const int FailReason1 = 1;
    public const int FailReason2 = 2;
    //Etc...
}

Это позволит вам сделать это.

public static int main(string[] args){
    return ReturnValue.Success;
}

ИЗМЕНИТЬ

Если вы хотите предоставить значения для перечисления, это когда вы хотите их объединить. См. Пример ниже:

[Flags] // indicates bitwise operations occur on this enum
public enum DaysOfWeek : byte // byte type to limit size
{
    Sunday = 1,
    Monday = 2,
    Tuesday = 4,
    Wednesday = 8,
    Thursday = 16,
    Friday = 32,
    Saturday = 64,
    Weekend = Sunday | Saturday,
    Weekdays = Monday | Tuesday | Wednesday | Thursday | Friday
}

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

public static class DaysOfWeekEvaluator
{
    public static bool IsWeekends(DaysOfWeek days)
    {
        return (days & DaysOfWeek.Weekend) == DaysOfWeek.Weekend;
    }

    public static bool IsAllWeekdays(DaysOfWeek days)
    {
        return (days & DaysOfWeek.Weekdays) == DaysOfWeek.Weekdays;
    }

    public static bool HasWeekdays(DaysOfWeek days)
    {
        return ((int) (days & DaysOfWeek.Weekdays)) > 0;
    }

    public static bool HasWeekendDays(DaysOfWeek days)
    {
        return ((int) (days & DaysOfWeek.Weekend)) > 0;
    }
}

Ответ 2

Перечень С# бесполезен.

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

  • Предоставить неявный оператор для преобразования из вашего типа в общий int, поэтому вам не нужно делать бросок.
  • Предоставляет явный оператор для преобразования из int в ваш тип, который выдает ошибку, если целое число не отвечает ограничению, например (int x) = > (x >= 0 && x <= = 2).

При использовании этого метода создайте универсальный неизменный базовый класс, такой как ConstrainedNumber<T>, который имеет конструктор, который принимает значение T и делегирует для ограничения: delegate bool NumberConstraint<T>(T value). Конструктор должен запускать значение через делегат ограничения и вызывать исключение, если ему не удается выполнить ограничение. Базовый класс должен также позаботиться о операции неявного преобразования в T и должен обрабатывать равенство, перегружая object.Equals(object) и object.GetHashCode(), определяя == и!= Операторы для типа ConstrainedNumber<T> и реализуя IEquatable<T> и IEquatable<ConstrainedNumber<T>>. Я также рекомендую определить конструктор копирования для базового класса и всех производных типов. Клонирование затем может быть реализовано чисто в базовом классе путем извлечения конструктора копирования посредством отражения, но это совершенно необязательно. Вы можете определить реализацию ConstrainedNumber<T> самостоятельно, если я уже не разместил ее где-то в stackoverflow.

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

public sealed class ReturnValue: ConstrainedNumber<int>
{
    public static readonly NumberConstraint<int> constraint = (int x) => (x >= 0 && x < 3);

    public static readonly ReturnValue Success = new ReturnValue(0);
    public static readonly ReturnValue FailReason1 = new ReturnValue(1);
    public static readonly ReturnValue FailReason2 = new ReturnValue(2);

    private ReturnValue( int value ): base( value, constraint ) {}
    private ReturnValue( ReturnValue original ): base (original) {} //may be used to support IClonable implementation in base class
    public static explicit operator ReturnValue( int value )
    {
        switch(value) //switching to return an existing instance is more efficient than creating a new one and re-checking the constraint when there is a limited number of allowed values; if the constraint was more generic, such as an even number, then you would instead return a new instance here, and make your constructors public.
        {
            case 0: return Success;
            case 1: return FailReason1;
            case 2: return FailReason2;
        }
        throw new ArgumentException( "Value fails to meet the constraint defined for " + typeof(ReturnValue).FullName + ".", "value" );
    }

}

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

Его можно использовать следующим образом:

EvenNumber x = (EvenNumber)2;
EvenNumber y = (EvenNumber)3; //throws exception "Value fails to meet the constraint defined for {namespace}.EvenNumber."  A c# enum would stupidly allow such a cast, creating an invalid EvenNumber, breaking the object-oriented model
int z = x; //implicit conversion, no cast necessary;

Ответ 3

Нет никакого неявного приведения, потому что перечисление не должно использовать int в качестве базового типа. Если в вашем перечислении используется uint в качестве базового типа, например, нет никакого неявного перевода из uint в int.

Ответ 4

Перечисления и ints просто неявно не могут быть закрыты в соответствии с спецификацией (кроме литерала 0, который разрешен для сравнительных тестов/присвоений/etc). Явное приведение - это все, что необходимо.

Ответ 5

Нет, вы не можете избежать кастинга; о том, почему нет явного преобразования, я не знаю, но там нет.

Ответ 6

Как ни странно, это не относится к .NET Framework, а только к С#. Как уже отмечали другие комментаторы, в С# это в основном спецификация языка. То же самое не относится к VB.NET.

Зайдите на страницу справки MSDN для Перечисления в VB.NET. Обратите внимание, что вы можете указать тип данных перечисления на время объявления Enum.

Это означает, что если вы действительно не хотите, чтобы ваш код был вытеснен с помощью меток (int), вы могли бы написать свое перечисление в VB.NET, объявить его как целое число, а затем использовать этот Enum из С#.

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

Ответ 7

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

Есть два отдельных вопроса для рассмотрения, связанные с вашим вопросом:

  • Значение Enum не может рассматриваться как int по умолчанию, потому что тогда вы сможете предоставить любое целое число, и не было бы проверки времени компиляции, чтобы проверить, что предоставленное целое число фактически существует как значение в Перечислении.

  • Кастинг становится необходимым, поскольку вы пытаетесь преобразовать из управляющего типа (типа YourCustomEnum, который происходит из класса System.Enum) в базовый тип, т.е. int или byte и т.д..

Ответ 8

Как насчет использования статических членов класса?

//enum DocInfos { DocName, DocNumber, DocVersion};
public class DocInfos
{
    public static int DocName = 0;
    public static int DocNumer = 1;
    public static int DocVersion = 2;
}

...

            Doc = new string[DocInfos.DocVersion];
            // Treffer
            Doc[DocInfos.DocName] = TrimB(HTMLLines[lineCounter + 2])

...