如何将对象的类型存储在变量中?
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 asNumber
是 5
,它是 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
作为元素,因为它是 Float
,isKindOf: 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"
我有一个 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 asNumber
是 5
,它是 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
作为元素,因为它是 Float
,isKindOf: 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"