Как мне сохранить тип объекта в переменной? - PullRequest
4 голосов
/ 03 мая 2019

У меня есть класс, которому необходимо передать тип элемента, поэтому позже я могу проверить, имеет ли другой объект тип или является подклассом этого типа, и добавить его во внутреннюю коллекцию.

У меня есть initialize: метод, который вызывается из new: ctor моего класса:

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 #.Это часть упражнения, поэтому, пожалуйста, извините надуманный пример:)

1 Ответ

5 голосов
/ 03 мая 2019

Как я уже упоминал в комментарии к вашему вопросу, проблема в том, что 5 asNumber - это 5, что является экземпляром SmallInteger, а не экземпляром Number.Таким образом, когда вы initialize: ваш класс с 5, то, что вы получаете в иваре 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, что 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"
...