我想创建一个包含枚举值的泛型类,并且还允许访问枚举的可能值。例如,可以考虑属性编辑器 - 您需要知道属性的当前值,并且还需要能够知道属性的其他值是合法的。并且不应提前知道枚举的类型,您应该能够使用任何类型的枚举。
我的第一个想法是这样的:
class EnumerationProperty[T <: Enumeration](value:T)
然而,这并不起作用,因为对于枚举T不是一个类型,它是一个对象。我尝试的其他变化是:
class EnumerationProperty[T <: Enumeration](value:T.Value)
class EnumerationProperty[T <: Enumeration.Value](value:T)
(我不会详细说明为什么这些不能正常工作,因为我怀疑这些原因并不有趣。)
答案 0 :(得分:5)
问题的第一部分。您可以像这样定义通用枚举值的持有者:
case class EnumerationProperty[T <: Enumeration#Value](value:T)
但我不知道如何在没有显式传递Enumeration对象的情况下获取所有枚举值。枚举具有values()
方法来获取所有值。 Enumeration#Value链接到Enumeration,但具有私有访问权限
答案 1 :(得分:3)
在您的用例(属性编辑器)中,我认为最好的解决方案是依赖scala 2.10中提供的scala反射。给定一个类TypeTag
,您可以获得其所有成员及其值的完整类型(不删除),并从中填充您的属性编辑器。对于枚举,请使用TypeTag
使用以下方法获取其值:
Using Scala 2.10 reflection how can I list the values of Enumeration?
现在,也许你不想要或不能使用scala反射,从现在开始,我认为情况就是如此。如果这是真的那么你正在打开一整套蠕虫:)
TL; DR:使用标准Enumeration
是不可能的,因此您可能必须明确地包装枚举值,如Ptharien's Flame&#39;的回答(或者你自己的Enumeration
分叉)。下面我详细介绍了我的所有尝试,请耐心等待。
不幸的是,由于某些未知原因(虽然我怀疑它与序列化问题有关),Enumeration.Value
没有指向其Enumeration
实例的字段。鉴于如何实现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 ...
在Enumeration
中被声明为final,所以无法覆盖它。 (再次注意,分叉Enumeration
将允许循环使用。实际上,为什么不这样做,因为我们已经沿着使用自定义枚举anwyay的路径。我将让你判断。)
所以这是另一种看法:
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)
万岁?不,因为从Value
到ValueWithEnum
的转换仅在访问red.enum
时完成,而不是在Colors
枚举实例化时完成。换句话说,当调用enum
时,编译器需要知道枚举的确切静态类型(编译器必须静态地知道红色的类型是Colors.Value
,而不仅仅是Enumeration# Value
})。在你提到的用例(属性编辑器)中你只能依赖于java反射(我已经假设你不会使用scala反射)来获取枚举值的类型,而java反射只会给你Enumeration#Val
{延伸Enumeration#Value
)作为Colors.Red
的类型。所以基本上你被困在这里。
你最好的选择是首先使用scala反射。
答案 2 :(得分:0)
class EnumProps[E <: Enumeration](val e: E)(init: e.Value) {...}
然后,您可以使用e
和e.Value
来实现该课程。