【问题标题】:What's the equivalent of Java's enum in C#? [duplicate]C# 中的 Java 枚举相当于什么? [复制]
【发布时间】:2009-09-03 22:31:51
【问题描述】:

C# 中 Java 的枚举相当于什么?

【问题讨论】:

  • 也许我想多了,但我希望您已经了解 C# 的枚举,并且您所指的 Java 的枚举有一些功能。如果是这样,也许您可​​以详细说明您的问题。
  • 如果你对Java有所了解,这个问题就很清楚了enums。
  • @Yishai - 在 c# 枚举中默认为 Int32,但可以更改为任何数字类型

标签: c# java enums


【解决方案1】:

完整的 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);
        }
    }
}

当然,您必须使用嵌套类型,但它们提供了方便的“自定义行为”部分,Java 枚举非常适合。在其他情况下,您只需将参数传递给私有构造函数即可获取众所周知的受限值集。

这并没有给你一些东西:

  • 顺序支持
  • 开关支持
  • EnumSet
  • 序列化/反序列化(作为单例)

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

哦,部分类型意味着您不必将所有枚举值放在同一个文件中。如果每个值都参与其中(这绝对是可能的),那么每个值都可以有自己的文件。

【讨论】:

  • 我认为通过使用到 int 的隐式转换来支持 switch 语句(和序数)是微不足道的,对吧?我忽略了什么?
  • @LimitedAtonement:您如何表示 case 表达式所需的 constant 值?
  • 我最近读了你的文章,关于有几次非私有字段是合理的。这是那个时代之一吗?
  • @AndrewCooper:是的——尽管有些人可能更喜欢通过属性公开这些。
  • 我喜欢这个解决方案,它启发了我最近在从 Java 到 C# 的移植中所做的一些工作。我想出了一个我认为是由Enumeration 基类支持的有趣解决方案,它增加了序数和名称支持。有关详细信息,请参阅我的答案。我打算很快写这篇博客,但首先感谢您对我的解决方案的反馈。
【解决方案2】:

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

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

您是否特别在寻找某些功能?

【讨论】:

  • “它们的工作方式相同”- 不是 IMO,因为常量不能有自定义 行为,这与 Java 枚举值不同。
  • 是的,因此是“基本使用”的资格。我同意 java 枚举的优点之一是自定义行为
  • 我喜欢 Java 枚举而不是 C# 枚举。使用 C# Enums,您会散布很多 Switch 语句的味道,而这些散布在 switch 语句中的大量代码本可以作为与每个 Enum 相关联的方法放置。
【解决方案3】:

这是另一个有趣的想法。我想出了以下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; }
    }
}

它基本上有一个类型参数,因此序数可以在不同的派生枚举中正常工作。上面 Jon 的 Operator 示例变为:

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

这有一些好处。

  • 顺序支持
  • 转换为 stringint 使 switch 语句可行
  • GetType() 将为派生的 Enumeration 类型的每个值提供相同的结果。
  • System.Enum 中的静态方法可以添加到 Enumeration 基类中以实现相同的功能。

【讨论】:

  • 我正在做一些 Java 到 C# 的转换,所以一个月前我看了你的回答,并认为“我的需要有点太麻烦了”......现在我又回来了,看到一个更多价值,因为我需要“按(字符串)名称检索枚举”功能。赞一个!
  • @Andrew Cooper ,回复:“这有一些优势。* 序数支持 * 转换为 string 和 int 使 switch 语句可行” - 似乎这仍然没有提供 switch 语句支持,因为编译器抱怨case 语句需要一个常量值。它既不接受 (int) 强制转换也不接受 .Ordinal 值作为 const。
【解决方案4】:

在我们得到真正的枚举模式之前,您可能会使用我们在 Java 中使用的旧类型安全枚举模式(假设 C# 中的枚举模式真的不是注释所声称的类)。该模式在this page的中间之前描述

【讨论】:

    【解决方案5】:
    //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);
            }
        }
    }
    

    【讨论】:

      【解决方案6】:

      enum ,或者您是否需要 Java 枚举具有但 c# 没有的特别东西?

      【讨论】:

      • 在 Java 中,枚举可以为每个枚举、具有逻辑的方法和构造函数具有多个关联值。至少从 C# 3.0 开始,C# 枚举仍然只是一个常量列表,具有可能的关联值。
      • -1:Java 枚举so 比 C# 的枚举强大得多。
      • +1 来对抗 Kramii 的 -1。 C# 枚举可以具有扩展方法,以弥补其中一些功能的缺失。
      猜你喜欢
      • 2014-04-28
      • 2012-04-08
      • 1970-01-01
      • 1970-01-01
      • 2012-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多