简体   繁体   中英

Smalltallk - How can I get an Array (or Collection) of the all the Instance variables in an Object (the current Instance) of a Class?

Let's say we have a Class and we instantiate it, creating an Instance of that Class. This Instance has a number of (instance)variables, defined by the class, that I need to use. I'd like to get all these (instance)variables in an Array or some Collection so I can iterate through them and set them to some value, not nil.

How can I do this?

I would like to build up on @Uko's answer because there is a more direct way to implement his idea.

The message instSize sent to a Class will answer the number of named instance variables of its instances. This, of course, would include instance variables defined in superclasses.

For instance, RemoteTempVectorNode instSize answers with 17 (wow!). Therefore you could do:

fields := (1 to: anObject class instSize) collect: [:i | anObject instVarAt: i]

and then, change them with:

values withIndexDo: [:v :i | anObject instVarAt: i put: v]

where values is the array of new values you want to inject into the object.

So, why I'm suggesting this instead of instVarNamed: ? Because the latter is indirect. If you take a look at its implementation you will see that it has to first find out the name of the i-th ivar by sending instVarIndexFor:ifAbsent: to the object's class. In other words, if you need the ivar names, follow @Uko's suggestion; otherwise don't bring them into the equation because they will only add CPU cycles to your program.

One more thing . As @Sean DeNegris wisely raised in his comment to your question, it would be beneficial if you elaborated a little bit more on why you need such an unusual maneuver.


EDIT:

Now that Pharo has Flexible Object Layouts the mapping between inst var names and the class instSize is no longer valid (in classes that use the new capability.) So, the simpler approach of using just indexes would not work with generality. In fact, under the new "taxonomy" the instSize (number of fields) of an object may be different from the #numberOfInstanceVariables . I guess that the added flexibility has its costs and benefits.

You can send #allInstVarNames to a class (Behavior) to get names of all instance variables defined by it and by superclasses. If you need without superclass variables, you can use #instVarNames

Let's say that var is your variable that you need to work with. Then you can get the collection of instance variable names and iterate them.

You can use #instVarNamed:put: to set instance variable by name, and #instVarNamed: to get the value by name (in case you need).

I think that something like this may help you:

var class allInstVarNames do: [ :instVarName |
  var instVarNamed: instVarName put: <yourValue>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM