什么是 C# 中 Java 枚举的等价物?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1376312/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 16:19:40  来源:igfitidea点击:

What's the equivalent of Java's enum in C#?

c#javaenums

提问by Nosrama

What's the equivalent of Java's enum in C#?

什么是 C# 中 Java 枚举的等价物?

回答by Jon Skeet

Full Java enum functionality isn't available in C#. You can come reasonablyclose using nested types and a private constructor though. For example:

完整的 Java 枚举功能在 C# 中不可用。不过,您可以使用嵌套类型和私有构造函数来合理地接近。例如:

using System;
using System.Collections.Generic;
using System.Xml.Linq;

public abstract class Operator
{
    public static readonly Operator Plus = new PlusOperator();
    public static readonly Operator Minus = 
         new GenericOperator((x, y) => x - y);
    public static readonly Operator Times = 
         new GenericOperator((x, y) => x * y);
    public static readonly Operator Divide = 
         new GenericOperator((x, y) => x / y);

    // Prevent other top-level types from instantiating
    private Operator()
    {
    }

    public abstract int Execute(int left, int right);

    private class PlusOperator : Operator
    {
        public override int Execute(int left, int right)
        {
            return left + right;
        }
    }

    private class GenericOperator : Operator
    {
        private readonly Func<int, int, int> op;

        internal GenericOperator(Func<int, int, int> op)
        {
            this.op = op;
        }

        public override int Execute(int left, int right)
        {
            return op(left, right);
        }
    }
}

Of course you don't haveto use nested types, but they give the handy "custom behaviour" part which Java enums are nice for. In other cases you can just pass arguments to a private constructor to get a well-known restricted set of values.

当然你不具备使用嵌套类型,但他们给了方便的“自定义的行为”其中一部分的Java枚举是好的。在其他情况下,您只需将参数传递给私有构造函数即可获得一组众所周知的受限值。

A few things this doesn't give you:

这并没有给你一些东西:

  • Ordinal support
  • Switch support
  • EnumSet
  • Serialization/deserialization (as a singleton)
  • 顺序支持
  • 开关支持
  • EnumSet
  • 序列化/反序列化(作为单例)

Some of that could probably be done with enough effort, though switch wouldn't really be feasible without hackery. Now if the languagedid something like this, it could do interesting things to make switch work by making the hackery automatic (e.g. declaring a load of constfields automatically, and changing any switch over the enum type to a switch over integers, only allowing "known" cases .)

其中一些可能需要足够的努力才能完成,但如果没有黑客技术,switch 就真的不可行。现在,如果语言做了这样的事情,它可以做一些有趣的事情,通过使黑客自动化(例如自动声明const字段负载,并将枚举类型的任何切换更改为整数切换,只允许“已知” ”的情况。)

Oh, and partial types mean you don't have to have allof the enum values in the same file. If each value got quite involved (which is definitely possible) each could have its own file.

哦,部分类型意味着您不必在同一个文件中包含所有枚举值。如果每个值都非常复杂(这绝对是可能的),每个值都可以有自己的文件。

回答by Chi

Enums are one of the few language features that is better implemented in java than c#. In java, enums are full fledged named instances of a type, while c# enums are basically named constants.

枚举是少数在 java 中实现得比 c# 更好的语言特性之一。在 java 中,枚举是一个类型的完整命名实例,而 c# 枚举基本上是命名常量。

That being said, for the basic case, they will look similar. However in java, you have more power, in that you can add behavior to the individual enums, as they are full fledged classes.

话虽如此,对于基本情况,它们看起来很相似。但是,在 Java 中,您拥有更多的权力,因为您可以向各个枚举添加行为,因为它们是成熟的类。

is there some feature in particular you are looking for?

有什么特别是您正在寻找的功能吗?

回答by Andrew Cooper

Here's another interesting idea. I came up with the following Enumerationbase class:

这是另一个有趣的想法。我想出了以下Enumeration基类:

public abstract class Enumeration<T>
    where T : Enumeration<T>
{   
    protected static int nextOrdinal = 0;

    protected static readonly Dictionary<int, Enumeration<T>> byOrdinal = new Dictionary<int, Enumeration<T>>();
    protected static readonly Dictionary<string, Enumeration<T>> byName = new Dictionary<string, Enumeration<T>>();

    protected readonly string name;
    protected readonly int ordinal;

    protected Enumeration(string name)
        : this (name, nextOrdinal)
    {
    }

    protected Enumeration(string name, int ordinal)
    {
        this.name = name;
        this.ordinal = ordinal;
        nextOrdinal = ordinal + 1;
        byOrdinal.Add(ordinal, this);
        byName.Add(name, this);
    }

    public override string ToString()
    {
        return name;
    }

    public string Name 
    {
        get { return name; }
    }

    public static explicit operator int(Enumeration<T> obj)
    {
        return obj.ordinal;
    }

    public int Ordinal
    {
        get { return ordinal; }
    }
}

It's got a type parameter basically just so the ordinal count will work properly across different derived enumerations. Jon's Operatorexample above then becomes:

它基本上有一个类型参数,因此序数计数将在不同的派生枚举中正常工作。JonOperator上面的例子变成了:

public class Operator : Enumeration<Operator>
{
    public static readonly Operator Plus = new Operator("Plus", (x, y) => x + y);
    public static readonly Operator Minus =  new Operator("Minus", (x, y) => x - y);
    public static readonly Operator Times =  new Operator("Times", (x, y) => x * y);
    public static readonly Operator Divide = new Operator("Divide", (x, y) => x / y);

    private readonly Func<int, int, int> op;

    // Prevent other top-level types from instantiating
    private Operator(string name, Func<int, int, int> op)
        :base (name)
    {
        this.op = op;
    }

    public int Execute(int left, int right)
    {
        return op(left, right);
    }
}

This gives a few advantages.

这提供了一些优点。

  • Ordinal support
  • Conversion to stringand intwhich makes switch statements feasible
  • GetType() will give the same result for each of the values of a derived Enumeration type.
  • The Static methods from System.Enumcan be added to the base Enumeration class to allow the same functionality.
  • 顺序支持
  • 转换为stringandint使 switch 语句可行
  • GetType() 将为派生的枚举类型的每个值提供相同的结果。
  • System.Enum可以将来自的静态方法添加到基本 Enumeration 类以允许相同的功能。

回答by Bill K

You could probably use the old typesafe enum pattern that we used in Java before we got real ones (assuming that the ones in C# really aren't classes as a comment claims). The pattern is described just before the middle of this page

在获得真正的枚举模式之前,您可能可以使用我们在 Java 中使用的旧类型安全枚举模式(假设 C# 中的那些真的不是注释声明的类)。该模式描述在本页中间之前

回答by Jim

//Review the sample enum below for a template on how to implement a JavaEnum.
//There is also an EnumSet implementation below.

public abstract class JavaEnum : IComparable {
    public static IEnumerable<JavaEnum> Values {
        get {
            throw new NotImplementedException("Enumeration missing");
        }
    }

    public readonly string Name;

    public JavaEnum(string name) {
        this.Name = name;
    }

    public override string ToString() {
        return base.ToString() + "." + Name.ToUpper();
    }

    public int CompareTo(object obj) {
        if(obj is JavaEnum) {
            return string.Compare(this.Name, ((JavaEnum)obj).Name);
        } else {
            throw new ArgumentException();
        }
    }


    //Dictionary values are of type SortedSet<T>
    private static Dictionary<Type, object> enumDictionary;
    public static SortedSet<T> RetrieveEnumValues<T>() where T : JavaEnum {
        if(enumDictionary == null) {
            enumDictionary = new Dictionary<Type, object>();
        }
        object enums;
        if(!enumDictionary.TryGetValue(typeof(T), out enums)) {
            enums = new SortedSet<T>();
            FieldInfo[] myFieldInfo = typeof(T).GetFields(BindingFlags.Static | BindingFlags.DeclaredOnly | BindingFlags.Public);
            foreach(FieldInfo f in myFieldInfo) {
                if(f.FieldType == typeof(T)) {
                    ((SortedSet<T>)enums).Add((T)f.GetValue(null));
                }
            }
            enumDictionary.Add(typeof(T), enums);
        }
        return (SortedSet<T>)enums;
    }
}


//Sample JavaEnum
public class SampleEnum : JavaEnum {
    //Enum values
    public static readonly SampleEnum A = new SampleEnum("A", 1);
    public static readonly SampleEnum B = new SampleEnum("B", 2);
    public static readonly SampleEnum C = new SampleEnum("C", 3);

    //Variables or Properties common to all enums of this type
    public int int1;
    public static int int2 = 4;
    public static readonly int int3 = 9;

    //The Values property must be replaced with a call to JavaEnum.generateEnumValues<MyEnumType>() to generate an IEnumerable set.
    public static new IEnumerable<SampleEnum> Values {
        get {
            foreach(var e in JavaEnum.RetrieveEnumValues<SampleEnum>()) {
                yield return e;
            }
            //If this enum should compose several enums, add them here
            //foreach(var e in ChildSampleEnum.Values) {
            //    yield return e;
            //}
        }
    }

    public SampleEnum(string name, int int1)
        : base(name) {
        this.int1 = int1;
    }
}


public class EnumSet<T> : SortedSet<T> where T : JavaEnum {
    // Creates an enum set containing all of the elements in the specified element type.
    public static EnumSet<T> AllOf(IEnumerable<T> values) {
        EnumSet<T> returnSet = new EnumSet<T>();
        foreach(T item in values) {
            returnSet.Add(item);
        }
        return returnSet;
    }

    // Creates an enum set with the same element type as the specified enum set, initially containing all the elements of this type that are not contained in the specified set.
    public static EnumSet<T> ComplementOf(IEnumerable<T> values, EnumSet<T> set) {
        EnumSet<T> returnSet = new EnumSet<T>();
        foreach(T item in values) {
            if(!set.Contains(item)) {
                returnSet.Add(item);
            }
        }
        return returnSet;
    }

    // Creates an enum set initially containing all of the elements in the range defined by the two specified endpoints.
    public static EnumSet<T> Range(IEnumerable<T> values, T from, T to) {
        EnumSet<T> returnSet = new EnumSet<T>();
        if(from == to) {
            returnSet.Add(from);
            return returnSet;
        }
        bool isFrom = false;
        foreach(T item in values) {
            if(isFrom) {
                returnSet.Add(item);
                if(item == to) {
                    return returnSet;
                }
            } else if(item == from) {
                isFrom = true;
                returnSet.Add(item);
            }
        }
        throw new ArgumentException();
    }

    // Creates an enum set initially containing the specified element(s).
    public static EnumSet<T> Of(params T[] setItems) {
        EnumSet<T> returnSet = new EnumSet<T>();
        foreach(T item in setItems) {
            returnSet.Add(item);
        }
        return returnSet;
    }

    // Creates an empty enum set with the specified element type.
    public static EnumSet<T> NoneOf() {
        return new EnumSet<T>();
    }

    // Returns a copy of the set passed in.
    public static EnumSet<T> CopyOf(EnumSet<T> set) {
        EnumSet<T> returnSet = new EnumSet<T>();
        returnSet.Add(set);
        return returnSet;
    }

    // Adds a set to an existing set.
    public void Add(EnumSet<T> enumSet) {
        foreach(T item in enumSet) {
            this.Add(item);
        }
    }

    // Removes a set from an existing set.
    public void Remove(EnumSet<T> enumSet) {
        foreach(T item in enumSet) {
            this.Remove(item);
        }
    }
}

回答by leeeroy

enum, or do you need something in particular that Java enums have but c# doesn't ?

enum,或者您是否需要 Java 枚举具有但 c# 没有的特定内容?