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

时间:2019-05-03 15:26:33

标签: smalltalk pharo

我有一个需要传递元素类型的类,因此以后我可以检查另一个对象是否具有该类型或该类型的子类,并将其添加到内部集合中。

我有一个initialize:方法,可以从我班上的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)之类的东西。这是练习的一部分,因此请原谅示例:)

1 个答案:

答案 0 :(得分:5)

正如我在对您的问题的评论中提到的那样,问题在于5 asNumber5,它是SmallInteger的实例,而不是Number的实例。因此,当您使用initialize: 5上课时,在ivar type中得到的内容是SmallInteger。然后,当您add: 5.4时,检查变成5.4 isKindOf: SmallInteger,这自然会失败。

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

initialize: aClass
  elements := OrderedCollection new.
  type := aClass

然后,您的示例将类似于

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

将接受5.4作为元素,因为它是Float的{​​{1}}。

现在让我补充一句话。 isKindOf: Number的常用语义不同于您使用的语义。 new:的参数通常是new:,并且此类和整数表示新实例的所需大小。例如,当您想要具有Integer个条目的Array new: 3时说Array,等等。3预期不会收到其他类型的参数来构造宾语。我并不是说这是禁止的,只是那不是通常的命名约定。在您的情况下,我建议使用一种创建实例的方法,例如

new:

您的代码看起来像

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