在C#中表示参数化枚举的最佳方法?

时间:2020-03-05 18:54:30  来源:igfitidea点击:

有没有好的解决方案来表示C3.0中的参数化枚举?我正在寻找类似OCaml或者Haxe的东西。我现在只能考虑使用简单的枚举字段进行轻松切换的类层次结构,也许有更好的主意?

请参阅以下回复之一中的Ocaml示例,Haxe代码如下:

enum Tree {
   Node(left: Tree, right: Tree);
   Leaf(val: Int);
}

解决方案

回答

C(据我所知,通常是.NET框架)不像Java那样支持参数化枚举。话虽这么说,我们可能想看看属性。 Java枚举所具有的某些功能可以通过属性来实现。

回答

仅为此使用类有什么问题?这很丑陋,但这就是Java人员在集成了Enum语言支持之前是如何做到的!

回答

我不熟悉OCaml或者Haxe,也不够聪明,无法理解其他解释,所以我去查阅了Haxe枚举文档,底部的" Enum Type Parameters"位似乎是相关的部分。

基于此,我的理解如下:

"正常"枚举基本上是一个值,该值仅限于我们在枚举定义中定义的内容。 C示例:

enum Color{ Red, Green, Yellow, Blue };
Color c = Color.Red;

c可以是红色,绿色,黄色或者蓝色,但没有别的。

在Haxe中,我们可以向枚举添加复杂类型,这是从它们的页面创建的示例:

enum Cell<T>{ 
  empty; 
  cons( item : T, next : Cell<T> )
}

Cell<int> c = <I don't know>;

这似乎意味着" c"被限制为字面值"空"(例如我们的老式Cenums),也可以是复杂类型" cons(item,next)",其中" item"是一个" T",而"下一个"是一个" Cell <T>"。

从未使用过它,看起来好像可能会生成一些匿名类型(例如,当我们执行" new {Name ='Joe'}"时,Ccompiler的工作方式。
每当我们"访问"枚举值时,都必须在声明时声明" item"和" next",并且看起来它们已绑定到临时局部变量。

Haxe示例我们可以看到'next'被用作临时本地变量,以将数据从匿名cons结构中拉出:

switch( c ) {
  case empty : 0;
  case cons(item,next): 1 + cell_length(next);
}

老实说,当我"点击"它似乎正在做的事情时,这让我大吃一惊。它似乎非常强大,我可以理解为什么我们会在C#中寻找类似的功能。

Cenum与最初复制它们的C / ++枚举几乎相同。基本上,这是说#define Red 1的一种好方法,因此,当我们传递Color对象时,编译器可以使用整数而不是字符串进行比较和存储。

在Cwould中,我这样做的目的是使用泛型和接口。像这样的东西:

public interface ICell<T> {
   T Item{ get; set; }
   ICell<T>{ get; set; }
}

class Cons<T> : ICell<T> {
  public T Item{ get; set; } /* C#3 auto-backed property */
  public Cell<T> Next{ get; set; }
}

class EmptyCell<T> : ICell<T>{
  public T Item{ get{ return default(T); set{ /* do nothing */ }; }
  public ICell<T> Next{ get{ return null }; set{ /* do nothing */; }
}

然后,我们可以拥有一个包含项目和下一个单元格的" List <ICell <T >>",并且可以在末尾插入" EmptyCell"(或者只是将" Next"引用显式设置为null)。
优点是因为EmptyCell不包含任何成员变量,所以不需要任何存储空间(例如Haxe中的empty),而Cons则需要。
编译器还可以内联/优化" EmptyCell"中的方法,因为它们什么都不做,因此与将成员数据设置为null的" Cons"相比,可能会提高速度。

我真的不知道我欢迎任何其他可能的解决方案,因为我对自己的解决方案并不感到特别自豪:-)

回答

使用具有静态属性的类来表示枚举值。我们可以选择使用私有构造函数来强制所有对该类的引用都经过一个静态属性。

看一下System.Drawing.Color类。它使用这种方法。