Czy mogę uniknąć rzucania wartości enum, gdy próbuję ją użyć lub zwrócić?

Jeśli mam następujące enum:

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

Czy mogę uniknąć rzucania po powrocie, w ten sposób:

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

Jeśli nie, to dlaczego wartość enum nie jest domyślnie traktowana jako int?

Author: Mark Carpenter, 2009-02-23

8 answers

Liczby powinny być bezpieczne dla typu. Myślę, że nie uczynili ich dorozumianymi, aby zniechęcić do innych zastosowań. Chociaż ramy pozwalają przypisać im stałą wartość, powinieneś ponownie rozważyć swój zamiar. Jeśli używasz głównie enum do przechowywania wartości stałych, rozważ użycie klasy statycznej:

public static class ReturnValue
{
    public const int Success = 0;
    public const int FailReason1 = 1;
    public const int FailReason2 = 2;
    //Etc...
}
To ci na to pozwala.
public static int main(string[] args){
    return ReturnValue.Success;
}

EDIT

Kiedy Czy chcesz podać wartości do enum jest wtedy, gdy chcesz je połączyć. Zobacz poniższy przykład:

[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
}

To wyliczenie może być następnie wykorzystane przy użyciu bitowej matematyki. Zobacz poniższy przykład dla niektórych aplikacji.

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;
    }
}
 49
Author: Michael Meadows,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-23 20:08:56

Nie ma Cast implicit, ponieważ enum nie musi używać int jako podstawowego typu. Jeśli Twoje enum używało uint jako podstawowego typu, na przykład, nie ma ukrytego cast od uint do int.

 4
Author: tvanfosson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-23 15:20:32

C # enum jest bezużyteczne.

Możesz uniknąć odlewania z twojego typu i ograniczyć wartości, które mogą być jawnie rzucane do twojego typu, tworząc klasę zamkniętą i dostarczając implicit / explicit operatory konwersji.

  • podaj Operator niejawny do konwersji z twojego typu na ogólny int, więc nie musisz rzucać.
  • podaj operator jawny do konwersji z int na typ, który wyświetla błąd, jeśli liczba całkowita nie spełnia ograniczenia, takie jak (int X) = > (x > = 0 & & x

Jeśli użyjesz tej techniki, Utwórz ogólną niezmienną klasę bazową, taką jak ConstrainedNumber<T>, która ma konstruktor, który akceptuje wartość T i deleguje dla ograniczenia: delegate bool NumberConstraint<T>(T value). Konstruktor powinien uruchomić wartość za pomocą delegata ograniczenia i wyrzucić wyjątek, jeśli nie spełnia tego ograniczenia. Klasa bazowa powinna również zająć się domyślną operacją konwersji na T i powinna obsłużyć równość przez przeciążenie obiektu.Equals(obiekt) i sprzeciw.GetHashCode (), definiowanie = = i != operatory dla typu ConstrainedNumber<T> oraz implementujące IEquatable<T> i IEquatable<ConstrainedNumber<T>>. Zalecam również zdefiniowanie konstruktora kopiującego dla klasy bazowej i wszystkich typów pochodnych. Klonowanie może być zaimplementowane w klasie bazowej poprzez pobranie konstruktora kopiującego przez reflection, ale jest to całkowicie opcjonalne. Możesz sam wymyślić ConstrainedNumber<T> implementację, chyba że gdzieś ją już wrzuciłem na stackoverflow.

Możesz podać named static wartości readonly w pochodnej ConstrainedNumber, dzięki czemu można uzyskać do nich dostęp tak jak do enum.

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" );
    }

}

Możesz użyć tej techniki dla każdego ograniczenia. Na przykład, klasa o nazwie EvenNumber może mieć ograniczenie, które zwraca true, jeśli podana liczba jest parzysta. W takim przypadku wystarczy upublicznić konstruktory i uprościć Operator konwersji statycznej, aby po prostu zwrócił nowy numer EvenNumber, zamiast przełączać się na zwracanie jednego z ograniczonych istniejących wystąpień.

Może być używane w ten sposób:

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;
 4
Author: Triynko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-10 16:23:35

Enums i ints po prostu nie są domyślnie rzucane zgodnie ze specyfikacją(z wyjątkiem dosłownego 0, które jest dozwolone dla testów porównawczych / zadań / etc). Tylko wyraźna obsada jest potrzebna.

 2
Author: Marc Gravell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-23 15:15:59

Nie, Nie można uniknąć castingu; co do tego, dlaczego nie ma ukrytej konwersji, Nie wiem, ale nie ma.

 0
Author: mquander,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-23 15:16:17

O dziwo, nie jest to specyficzne dla. NET Framework, ale tylko dla C#. Jak już zauważyli inni komentatorzy, w C# jest to w zasadzie specyfikacja języka. To samo nie jest prawdą w VB.NET.

Sprawdź stronę referencyjną MSDN dla Enums w VB.NET . zauważ, że możesz określić typ danych wyliczenia w czasie deklaracji wyliczenia.

Oznacza to, że jeśli naprawdę nie chcesz zaśmiecać kodu za pomocą (int), możesz napisać Twoje wyliczenie w VB.NET, zadeklaruj go jako liczbę całkowitą, a następnie użyj tego Enum z C#.

Pamiętasz, jak mówili nam, że komputery ułatwią nam życie? :)

 0
Author: Mike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-23 15:26:48

Możesz przypisać to zachowanie do podstawowej intencji tworzenia wyliczeń... aby utworzyć zestaw nazwanych stałych, które mogą mieć tylko określone (lub domyślne) wartości w zależności od typu bazowego.

Istnieją dwie odrębne kwestie do rozważenia, związane z twoim pytaniem:

  1. Wartość {[0] } nie może być domyślnie traktowana jako int, ponieważ wtedy można by podać dowolną liczbę całkowitą i nie będzie sprawdzania czasu kompilacji, aby potwierdzić, że podana liczba całkowita w rzeczywistości istnieje jako wartość w wyliczeniu.

  2. Odlewanie staje się konieczne, ponieważ próbujesz przekształcić Typ rządzący (typu YourCustomEnum, który wywodzi się z klasy System.Enum) na typ podstawowy, tj. int lub byte, itp.

 0
Author: Cerebrus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-23 15:29:19

Co powiesz na używanie statycznych członków klasy?

//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])

...

 -2
Author: Hajoseb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-01 19:01:49