首页 > 解决方案 > 如何将对象的类型存储在变量中?

问题描述

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

我有一个从我的班级的ctorinitialize:调用的方法: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) 的方法是错误的,但我找不到更好或更明确的确定类型的方法。基本上,我正在寻找类似typeOf(MyObject)C# 的东西。这是练习的一部分,所以请原谅人为的例子:)

标签: smalltalkpharo

解决方案


正如我在对您的问题的评论中提到的那样,问题在于5 asNumber哪个5是 的实例SmallInteger,而不是Number. 因此,当您在 ivar 中获得initialize:的课程是. 然后,当 you 时,检查变为,自然会失败。5typeSmallIntegeradd: 5.45.4 isKindOf: SmallInteger

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

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

然后,您的示例将类似于

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

which 可以5.4作为一个元素接受,因为它是 a Float, which isKindOf: Number

现在让我再补充一句。通常的语义与new:您使用的不同。的参数new:通常是一个Integer和这样的整数表示新实例的所需大小。例如,您说Array new: 3当您想要一个Array带有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"

推荐阅读