instance a class from its class name 
Author Message
 instance a class from its class name

Is it somehow possible to instance a class from its class name stored in a
string?

I tried:

    Dim iObj As Object
    Dim iClassName as String

    iClassName = "MyClassName"
    Set iObj = CreateObject("MyProjectName." & iClassName)

but I get Error 429.

Thanks.



Thu, 26 May 2011 10:52:42 GMT  
 instance a class from its class name
Hi Eduardo,

In VB6 you can't do this because the class is typically Private, and for
CreateObject or late bound scripting etc, it needs to be public.  So you
have to expose the class in a COM library. (ActiveX.dll etc)

Quote:

> Is it somehow possible to instance a class from its class name stored in a
> string?

> I tried:

>    Dim iObj As Object
>    Dim iClassName as String

>    iClassName = "MyClassName"
>    Set iObj = CreateObject("MyProjectName." & iClassName)

> but I get Error 429.

> Thanks.



Thu, 26 May 2011 11:11:04 GMT  
 instance a class from its class name


Quote:
> Is it somehow possible to instance a class from its class
> name stored in a string?

If you want to do this for project-private Classes,
then the following works well and fast enough
(the instantiation itself needs much more time than
the String-Check-Overhead).

'*** in a *.bas-module
Function GetInstanceByString(ClassName$) as Object
    Select Case LCase$(ClassName)
        Case "cmyclass1": Set GetInstanceByString = New cMyClass1
        Case "cmyclass2": Set GetInstanceByString = New cMyClass2
        'etc...
    End Select
Ed Function

Olaf



Thu, 26 May 2011 22:15:59 GMT  
 instance a class from its class name


Quote:


>> Is it somehow possible to instance a class from its class
>> name stored in a string?

> If you want to do this for project-private Classes,
> then the following works well and fast enough
> (the instantiation itself needs much more time than
> the String-Check-Overhead).

> '*** in a *.bas-module
> Function GetInstanceByString(ClassName$) as Object
>    Select Case LCase$(ClassName)
>        Case "cmyclass1": Set GetInstanceByString = New cMyClass1
>        Case "cmyclass2": Set GetInstanceByString = New cMyClass2
>        'etc...
>    End Select
> Ed Function

> Olaf

Yes, that is what i finally had to do, but i wanted to avoid this.

I wrote two general functions to convert Collections to Strings and to get
the Collection back from the string, and the problem is that when i later
try to reconstruct the objects of the collection from the string, i need to
instanciate the objects from their class names.

Now it is a pseudo general routine because i need to hardcode the class
names in a function.



Thu, 26 May 2011 23:45:06 GMT  
 instance a class from its class name


Quote:
> Yes, that is what i finally had to do, but i wanted to avoid this.
<...>
> Now it is a pseudo general routine because i need to hardcode the class
> names in a function.

Another route would have you use an interface in all your classes that
would provide methods for serialization and de-serialization.  You could
then write 'generic' code that targets the interface, and it would work
for all the classes that support that interface.  It would allow you to
write that 'generic' code, but at some point, you'll need to do the
Select Case to cast that object to the proper type, unless (for some
unknown reason) you want to work late bound with private objects.

LFS



Fri, 27 May 2011 01:36:22 GMT  
 instance a class from its class name


Quote:


>> Yes, that is what i finally had to do, but i wanted to avoid this.
> <...>
>> Now it is a pseudo general routine because i need to hardcode the class
>> names in a function.

> Another route would have you use an interface in all your classes that
> would provide methods for serialization and de-serialization.  You could
> then write 'generic' code that targets the interface, and it would work
> for all the classes that support that interface.  It would allow you to
> write that 'generic' code, but at some point, you'll need to do the
> Select Case to cast that object to the proper type, unless (for some
> unknown reason) you want to work late bound with private objects.

> LFS

Hi Larry:

I just wanted to work late bound because I wanted to write something truly
generic and then I wanted to avoid the hardcoded select case. But what I
didn't know is that it doesn't work for private objects.

Anyway, it is not really generic because there are some logical
requirements. For example: I had a class with code like this:

Private mCollectionOfObjects2 as Collection

Public Property Get Objects2 () as Collection
    Set Objects2 = mCollectionOfObjects2
End Property

' (and i added the objects to the collection in this way:)

Public Sub AddObject2 (nParameter1 as Long, nParameter2 as String,
nParameter3 as Single)
    Dim iObject2 as New Object2

    iObject2.Property1 = nParameter1
    iObject2.Property2 = nParameter2
    iObject2.Property3 = nParameter3

    mCollectionOfObjects2.Add iObject2
End Sub

Then, the conversion to String worked, but the re-conversion back to object
didn't, because it wasn't able to add the objects to the collection.

Then I had to add the procedure:

Public Property Set Objects2 (nCollection as Collection)
    Set mCollectionOfObjects2 = nCollection
End Property

And now the "generic" routine is able to add this collection of objects.

So, the conclusion is that all the properties that you need to preserve must
be writable. Because a generic routine could not know of specific ways to
construct objects, it just can read and write properties.



Fri, 27 May 2011 15:27:49 GMT  
 instance a class from its class name


Quote:
> I just wanted to work late bound because I wanted to write something truly
> generic and then I wanted to avoid the hardcoded select case. But what I
> didn't know is that it doesn't work for private objects.

> Anyway, it is not really generic because there are some logical
> requirements. For example: I had a class with code like this:

> Private mCollectionOfObjects2 as Collection

> Public Property Get Objects2 () as Collection
>     Set Objects2 = mCollectionOfObjects2
> End Property

You are breaking encapsulation here.  Suppose I grab that collection:

Set pub = ObjWithCol.Objects2()

Now code outside the class has a reference to the private collection.
If you want to destroy that class, you must first destroy the outside
reference (pub).  If the outside reference is never destroyed, you
would not be able to destroy that object.  Also, if outside code is
allowed to reference an internal collection, the collection isn't really
private,  is it?

<snipped for brievity>

Quote:
> So, the conclusion is that all the properties that you need to preserve must
> be writable. Because a generic routine could not know of specific ways to
> construct objects, it just can read and write properties.

Well, that was where the interface would have helped.  You can expose
what you want on the interface, and never let anyone else see what it
contains.  For example, suppose I want to expose a Name/Value object
where the name and value can only be set by my program.

If I add public properties for Name and Value, then anyone can reach
in and set their contents.  But if I add Get with no Let property, how
is my program going to set the values?  This was so common there
is the Friend identifier now, but the way to do that without using Friend
is to use an interface.

So now I just supply the Get properties to the public and implement
a private (MyEyesOnly) interface to expose the Let side.  The class
might look similar to:

Option Explicit
Implements MyEyesOnly

Private mName As String
Private mValue As Long

Public Property Get Name() As String
  Name = mName
End Property
Public Property Get Value() As Long
  Value = mValue
End Property

Private Sub MyEyesOnly_Init(Name As String, ByVal Value As Long)
  mName = Name
  mValue = Value
End Sub

With that I can hand that object out to anybody, and they can't change
the values.  To initialize an object, I might create a factory method to verify
the data and return the public object:

Public Function NewObject(Name as string, Value as long) As PublicObject
Dim meo as MyEyesOnly

  If NameIsValid(Name) And ValueIsValid(Value) Then
     Set NewObject = New PublicObject
     Set meo = NewObject
     meo.Init Name, Value
  End if

End Function

If you understand this all so far, you might realize that you could create
an interface that has ToString and FromString methods that get implemented
by your object classes, and by your collection classes.  One advantage is that
the (To/From string) implementation for the data in the objects, is in each
individual class module, which means, if you change the public data or
properties of a class, you also change the To/From string methods in that
same class, and no other classes are effected.  The class that has the data
knows how to go to and from a string, and its nobody else's business how
it does that.  (could be encrypted...)

So, if each of your objects implement a ToString method, and the ToString
method of your collection object aggregates all the ToString data from the
objects it contains, then simply calling the ToString method on the collection
object, gets all the data for all the objects.  The reverse (FromString) would
also be doable.

To make it robust enough to handle all different types of objects, the string
data would have to contain an identifier of what type of object it belongs
to.  Not a big problem, but something that needs design consideration....

I just thought I would complete the suggestion.  If you have something
that works, go with that, but be aware of the pitfalls if you expose a
private object out to the wild blue yonder....

<g>
LFS



Fri, 27 May 2011 18:28:14 GMT  
 instance a class from its class name


[I cut everything otherwise I would leave all your text]

In the way you suggest I understand that you need to hardcode the
implementation in each object. You need to write, or at least to copy the
"ToString" and "FromString" procedures.

You are right that my code breaks encapsulation, but it is not a component,
it is just inside my exe, so if someone reference an object, it will be me.

If you don't want to break encapsulation, then you need to replicate all and
every object that the class hold inside before exposing it to the outside.

BTW, the program that I'm writing (with this code) is just a hobby. I made a
quite simple collection of objects with some Classes chained. But I needed
persistance.
I didn't want to spend too much time writing code to use a database, then I
thought about what easy way could I use to save it to a file or to the
registry. Now I'm saving it to the registry and it's working fine, I'll see
what happen when the data of the object grow as I add more data using the
program, may be I'll have to change it to save the String to a file.

I performed some tests and VB allow Strings up to 240,000,000 characters
long (in my computer), and the registry much less, but still much: about
524,000 characters.



Fri, 27 May 2011 19:49:39 GMT  
 instance a class from its class name

Quote:


>> Private mCollectionOfObjects2 as Collection

>> Public Property Get Objects2 () as Collection
>>     Set Objects2 = mCollectionOfObjects2
>> End Property

> You are breaking encapsulation here.  Suppose I grab that collection:

> Set pub = ObjWithCol.Objects2()

> Now code outside the class has a reference to the private collection.
> If you want to destroy that class, you must first destroy the outside
> reference (pub).  If the outside reference is never destroyed, you
> would not be able to destroy that object.

I agree with you about the encapsulation concept, but in VB6 object lifetime
is independent from variable scope, and dependent only on reference count.
In the above case, the class can be destroyed even if the collection is not.
I think you already know this, but you were thinking about another
situation. Here is a sample, followed by the output it prints:

' Form1 code ===========================

Option Explicit

Dim oClass1 As Class1

Private Sub Form_Load()
    Dim MyCol As Collection
    Dim itm

    Set oClass1 = New Class1
    Set MyCol = oClass1.GetCollection()
    Set oClass1 = Nothing

    For Each itm In MyCol
        Debug.Print itm
    Next

    Set MyCol = Nothing
End Sub

' Class1 code ===========================

Option Explicit

Private col As Collection

Private Sub Class_Initialize()
    Set col = New Collection
    Debug.Print "Class_Initialize called"
    col.Add "Test1"
    col.Add "Test2"
End Sub

Private Sub Class_Terminate()
    Set col = Nothing
    Debug.Print "Class_Terminate called"
End Sub

Public Function GetCollection() As Collection
    Set GetCollection = col
End Function

' Output ===========================
Class_Initialize called
Class_Terminate called
Test1
Test2

The above shows that the instance/object was destroyed, but the collection
wasn't.



Sat, 28 May 2011 01:10:16 GMT  
 instance a class from its class name
Hi Eduardo,

<snip>

Quote:
>  Now I'm saving it to the registry and it's working fine, I'll see what
> happen when the data of the object grow as I add more data using the
> program, may be I'll have to change it to save the String to a file.

> I performed some tests and VB allow Strings up to 240,000,000 characters
> long (in my computer), and the registry much less, but still much: about
> 524,000 characters.

Just because you can doesn't mean you should.  You really should be using  a
file based storage for this, not registry.


Sat, 28 May 2011 04:21:58 GMT  
 instance a class from its class name



Quote:
> Hi Eduardo,


> <snip>
>>  Now I'm saving it to the registry and it's working fine, I'll see what
>> happen when the data of the object grow as I add more data using the
>> program, may be I'll have to change it to save the String to a file.

>> I performed some tests and VB allow Strings up to 240,000,000 characters
>> long (in my computer), and the registry much less, but still much: about
>> 524,000 characters.

> Just because you can doesn't mean you should.  You really should be using
> a file based storage for this, not registry.

Or what? Will i go to jail?


Sat, 28 May 2011 04:47:03 GMT  
 instance a class from its class name

Quote:



>> Hi Eduardo,


>> <snip>
>>>  Now I'm saving it to the registry and it's working fine, I'll see what
>>> happen when the data of the object grow as I add more data using the
>>> program, may be I'll have to change it to save the String to a file.

>>> I performed some tests and VB allow Strings up to 240,000,000 characters
>>> long (in my computer), and the registry much less, but still much: about
>>> 524,000 characters.

>> Just because you can doesn't mean you should.  You really should be using
>> a file based storage for this, not registry.

> Or what? Will i go to jail?

No but you will be slowing down users PCs as they need to load the registry
to start.


Sat, 28 May 2011 05:00:11 GMT  
 instance a class from its class name

Quote:
> [Addressed to Eduardo] No but you will be slowing down
> users PCs as they need to load the registry to start.

You'd have trouble slowing them down much more than Windoze Vista already
does!


Sat, 28 May 2011 05:19:27 GMT  
 instance a class from its class name


Quote:
>> Or what? Will i go to jail?

> No but you will be slowing down users PCs as they need to load the
> registry to start.

I see that I didn't specify: it's a hobby for me. It will run in my
computer.


Sat, 28 May 2011 05:26:32 GMT  
 instance a class from its class name

Quote:



>> No but you will be slowing down users PCs as they need to load the
>> registry to start.

> I see that I didn't specify: it's a hobby for me. It will run in my
> computer.

You are still better to write it to the file system, not the registry.  Just
because you choose to be a hobbyist, doesn't mean best practices should not
still apply.


Sat, 28 May 2011 05:45:13 GMT  
 
 [ 20 post ]  Go to page: [1] [2]

 Relevant Pages 

1. newbie: private class variables are visible in class instances

2. Find out if somebody make an instance of a Class without having access to the Class

3. nested class inherits containing class accessing private instance members

4. Create an instance from the class name?

5. Dim obj As New Class crt Dim Obj As Class = New Class

6. derive class from protected class in base class

7. File name or class name not found during Automation operation

8. Project-Name, dll-Name & Classes

9. Limitation in class name and method names

10. Error 432 (file name or class name not found during automation operation)

11. Name that control! - class name = toolbarwindow32

12. How to get Ole class name by file name extensions

 

 
Powered by phpBB® Forum Software