2

我想创建一个通用类来保存枚举的值,并且还允许访问枚举的可能值。以属性编辑器为例——您需要知道该属性的当前值,并且您还需要能够知道该属性还有哪些其他值是合法的。并且不应该事先知道枚举的类型,您应该能够使用任何类型的枚举。

我的第一个想法是这样的:

class EnumerationProperty[T <: Enumeration](value:T)

但是,这不起作用,因为对于枚举 T 不是类型,它是一个对象。我尝试过的其他变体是:

class EnumerationProperty[T <: Enumeration](value:T.Value)
class EnumerationProperty[T <: Enumeration.Value](value:T)

(我不会详细说明为什么这些不起作用,因为我怀疑原因并不有趣。)

4

3 回答 3

5

对于你问题的第一部分。您可以像这样为通用枚举值定义持有者:

case class EnumerationProperty[T <: Enumeration#Value](value:T)

但我不知道如何在不显式传递 Enumeration 对象的情况下获取所有枚举值。枚举具有values()获取所有值的方法。并且 Enumeration#Value 具有指向 Enumeration 的链接,但具有私有访问权限

于 2013-01-22T05:37:44.067 回答
3

在您的用例(属性编辑器)中,我认为最好的解决方案是依赖 scala 2.10 中可用的 scala 反射。给定一个类的TypeTag,您可以获得其所有成员的完整类型(无需擦除)以及它们的值,并从中填充您的属性编辑器。对于枚举,使用TypeTag以下方法获取它们的值: 使用 Scala 2.10 反射如何列出枚举的值?


现在,也许你不想或不能使用 scala 反射,从现在开始我会假设是这种情况。如果这是真的,那么您将打开一整罐蠕虫 :) TL;DR:这是不可能使用标准的Enumeration,因此您可能必须明确包装枚举值,如 Ptharien 的 Flame 的答案所示(或滚动您自己的的叉子Enumeration)。下面我详细介绍我的所有尝试,请多多包涵。

不幸的是,出于某种未知的原因(尽管我怀疑它与序列化问题有关),Enumeration.Value没有指向其Enumeration实例的字段。鉴于如何Enumeration实现,这将是微不足道的实现,但我们当然没有发言权,除了分叉枚举和修改我们的版本(这实际上是我为此目的所做的,加上对序列化和反射的适当支持 - 但是我离题了)。

如果我们不能修改Enumeration,也许我们可以扩展它?再次查看实现,这样的事情似乎可行:

class EnumerationEx extends Enumeration {
  protected class ValEx(i: Int, name: String) extends Val(i, name) {
    @transient val enum: Enumeration = EnumerationEx.this
  }
  override protected def Value(i: Int, name: String): Value = new ValEx(i, name)  
}

object Colors extends EnumerationEx {
  val Red, Green, Blue = Value
}

缺点是它仅适用于显式扩展EnumerationEx而不是 的枚举Enumeration,但总比没有好。

不幸的是,这不能编译,因为def Value ...它被声明为 final,Enumeration所以没有办法覆盖它。(再次注意,分叉Enumeration可以规避这一点。实际上,为什么不这样做,因为我们已经走上了使用自定义枚举的道路。我会让你判断)。

所以这是另一种看法:

class EnumerationEx extends Enumeration {
  class ValueWithEnum( inner: Value ) {
    @transient val enum: Enumeration = EnumerationEx.this
  }
  implicit def valueToValue( value: Value ): ValueWithEnum = new ValueWithEnum( value )
}

确实按预期工作。或者看起来是这样。

scala> object Colors extends EnumerationEx {
     |   val Red, Green, Blue = Value
     | }
defined module Colors

scala> val red = Colors.Red
red: Colors.Value = Red

scala> red.enum.values
res58: Enumeration#ValueSet = Colors.ValueSet(Red, Green, Blue)

万岁?不,因为从Valueto的转换ValueWithEnum仅在访问时完成red.enum,而不是在Colors枚举实例化时完成。换句话说,在调用enum编译器时需要知道枚举的确切静态类型(编译器必须静态知道 red 的类型是Colors.Value,而不仅仅是Enumeration# Value)。而在你提到的用例(属性编辑器)中,你只能依靠java反射(我已经假设你不会使用scala反射)来获取枚举值的类型,而java反射只会给你Enumeration#Val( extends Enumeration#Value) 作为 的类型Colors.Red。所以基本上你被困在这里。你最好的选择肯定是首先使用 scala 反射。

于 2013-01-22T09:26:56.063 回答
0
class EnumProps[E <: Enumeration](val e: E)(init: e.Value) {...}

然后你可以使用eande.Value来实现这个类。

于 2013-01-22T06:10:47.703 回答