如何将对象的类型存储在变量中?

How do I store the type of an object in a variable?

我有一个 class 需要传递元素的类型,所以我可以稍后检查另一个对象是否具有该类型或者是该类型的子 class 并添加它到一个内部集合。

我有一个 initialize: 方法,它从我的 class 的 new: 构造函数调用:

initialize: aType
    elements := OrderedCollection new.
    type := aType class.

现在我有一个方法可以传递一个值,应该检查类型是否兼容:

add: anElement  
    type isNil ifTrue: [ elements add:anElement. ^self. ].

    (anElement isMemberOf: type)
       ifTrue: [elements add:anElement.]
       ifFalse: [ ^ 'Not supported!' ].

如果我想检查具体类型,这会起作用:

|myClass|
myClass:= MyClass new: '123'.

cc add: '5.4'. "Works"
cc add: 123.  "Fails correctly."

现在,为了检查它是否是派生类型,我修改了 add: 方法:

add: anElement  
    type isNil ifTrue: [ elements add:anElement. ^self. ].

    (anElement isKindOf: type)
      ifTrue: [elements add:anElement.]
      ifFalse: [ ^ 'Not supported!' ].

但是,这不起作用:

|myClass|
myClass:= MyClass new: 5 asNumber.

myClass add: 5.4. "Fails, although Float is a sub type of Number"

我怀疑我最初确定对象类型的方法 (aType class) 是错误的,但我找不到更好或更明确的确定类型的方法。基本上,我在 C# 中寻找类似 typeOf(MyObject) 的东西。这是练习的一部分,所以请原谅人为的例子:)

正如我在对您的问题的评论中提到的,问题是 5 asNumber5,它是 SmallInteger 的一个实例,而不是 Number 的一个实例.因此,当你 initialize: 你的 class 和 5 你在 ivar type 中得到的是 SmallInteger。然后,当你 add: 5.4 时,检查变成 5.4 isKindOf: SmallInteger,这自然会失败。

我认为问题出在您选择初始化实例的方式上。一种更简单的方法是使用 class 而非实例显式设置目标 type。类似

的东西
initialize: aClass
  elements := OrderedCollection new.
  type := aClass

然后,您的示例将类似于

|myClass|
myClass:= MyClass new initialize: Number.
myClass add: 5.4.

接受 5.4 作为元素,因为它是 FloatisKindOf: Number.

现在让我再补充一点。 new: 的通常语义与您使用的语义不同。 new: 的参数通常是一个 Integer,这样的整数表示新实例的所需大小。例如,当您想要一个带有 3 条目的 Array 时,您说 Array new: 3 等。不希望 new: 接收其他类型的参数来构造目的。我并不是说这是禁止的,只是这不是通常的命名约定。在您的情况下,我会建议一种创建实例的方法,例如

MyClass class >> on: aClass
  ^self new initialize: aClass

你的代码看起来像

| sequence |
sequence := MyClass on: Number.
sequence add: 5.                        "ok, 5 isKindOf: Number"
sequence add: 4.5.                      "ok, 5.4 isKindOf: Number"
sequence add: 'hello world'             "fail, not a Number"