Create an object at runtime

D

Dave Taylor

I have a DataTable with three string columns, "Value", "Format" and "Type"

However, some of the rows contain numbers and dates in the Value field. So
I would like to be able to format the output based on the format specifier
in the Format field. The problem is, since the Value field is a string, it
doesnt properly "format".

So I need to convert to an object of the type specified by "Type"...ok, so
Activator.CreateInstance() BUT the problem is, the constructors dont take a
string argument.

So how do I create a new object of the specified type without knowing what
arguments it will need? There are no empty constructors that I can find.

I am mostly using DateTime, Single, Integer and String values as my "Type"

My weak attempt so far is shown below...any help is greatly appreciated.
Thanks

Dave Taylor

dv = CType(source.List, DataView)

drv = dv(rowNum)

szF = drv("Format")

szT = drv("Type")

szV = drv("Value")



'Convert the string to the appropriate type

If (szF <> "") Then

t = Type.GetType(szT)

v = Activator.CreateInstance(t) '**Error occurs here because of no 'empty
constructors' available

Try

v = szV

szV = Microsoft.VisualBasic.Format(v, szF)

Catch ex As InvalidCastException

'Ignore, just output the unformatted data if there is an error converting

End Try

End If
 
C

Cor

Hi Dave,

Can you show the code with what you construct your datatable.

I do not how your sample deals with that datatable.

Cor
 
D

Dave Taylor

Cor,

The code I attached is placed in the Paint method of a
DataGridTextboxColumn-derived class. The DataTable and associated DataView
objects work just fine.

The problem I'm having is creating a new object at runtime given only a
string containing its type and no arguments for its constructor. So
basically, if the Type field contains "DateTime" or "System.DateTime" I want
to create a new DateTime object. The Activator.CreateInstance is supposed
to do this, however, it seems to require arguments specific to each type,
else it throws an exception. My idea was to create an empty object of the
specified type and then use implicit conversion to get the value from my
"Value" string.

regards,


Dave
 
C

Cor

Hi Dave,

Where has that information to be.

In other words, is it a binded datagrid, is it back to the dataset.

That makes it difficult to see what you want.

I think I can understand the problem, but not the solution.

With a bounded datagrid, the "format" and "parse" events should work.
If not it seems to me a simple test of the value to know what has to be your
format.

But that is just from the information I got from you.

Because I do not understand why you needs the method you took.

Cor
 
A

Armin Zingler

Dave Taylor said:
Cor,

The code I attached is placed in the Paint method of a
DataGridTextboxColumn-derived class. The DataTable and associated
DataView objects work just fine.

The problem I'm having is creating a new object at runtime given only
a string containing its type and no arguments for its constructor.
So basically, if the Type field contains "DateTime" or
"System.DateTime" I want to create a new DateTime object. The
Activator.CreateInstance is supposed to do this, however, it seems to
require arguments specific to each type, else it throws an exception.
My idea was to create an empty object of the specified type and then
use implicit conversion to get the value from my
"Value" string.

I think the problem is that you don't actually want to create a new object
and fill it by a value afterwards. You just want to convert a string to a
variable data type. So IMO the question is which conversion functions are
there and how can they be called dynamically? I'd create a new Sytem.Type
object depending on the String "System.DateTime" (or whatever). Then invoke
the Type object's parse method using reflection and passing the value
string. Afterwards call the ToString method and pass the format string. HTH.


--
Armin

How to quote and why:
http://www.plig.net/nnq/nquote.html
http://www.netmeister.org/news/learn2quote.html
 
D

Dave Taylor

Armin,

Thanks for the reply. The Parse() method was exactly what I needed...my
code now looks like this and works fine. Thanks again.


Protected Overloads Overrides Sub Paint(ByVal g As System.Drawing.Graphics,
ByVal bounds As System.Drawing.Rectangle, ByVal source As
System.Windows.Forms.CurrencyManager, ByVal rowNum As Integer, ByVal
backBrush As System.Drawing.Brush, ByVal foreBrush As System.Drawing.Brush,
ByVal alignToRight As Boolean)

Dim drv As DataRowView, dv As DataView

Dim v As Object, szV As String, szF As String, szT As String

Dim rect As Rectangle

dv = CType(source.List, DataView)

drv = dv(rowNum)

szF = drv("Format")

szT = drv("Type")

szV = drv("Value")

If InStr(szT, ".") = 0 Then szT = "System." & szT

'Convert the string to the appropriate type

If (szF <> "") Then

Try

v = Activator.CreateInstance(Type.GetType(szT))

v = v.Parse(szV)

szV = Microsoft.VisualBasic.Format(v, szF)

Catch ex As InvalidCastException

'Ignore just output the unformatted data if there is an error converting

End Try

End If



rect = bounds

g.FillRectangle(backBrush, rect)

rect.Offset(0, 2)

rect.Height -= 2

g.DrawString(szV, Me.DataGridTableStyle.DataGrid.Font, foreBrush,
RectangleF.FromLTRB(rect.X, rect.Y, rect.Right, rect.Bottom))

If _bOwnerDraw Then _ctl.Invalidate()

End Sub
 
A

Armin Zingler

Dave Taylor said:
Armin,

Thanks for the reply. The Parse() method was exactly what I
needed...my code now looks like this and works fine. Thanks
again.

Some comments:
- I'd strongly recommend to enable Option Strict in the project properties.
You have to change the code like this:

szF = drv("Format").ToString
szT = drv("Type").ToString
szV = drv("Value").ToString

- The brackets around the expression with the If statement is superfluous:
If szF <> "" Then
Even better because faster:
If szf.Length > 0 Then

- I'd also use expressive names. szF, szT, szV is not very intuitive

- What I meant was that you do not need to create an instance using
activator.createinstance. Here a modified example (no intuitive names...):

Dim szV As String, szF As String, szT As String
Dim Result As String
Dim t As Type
Dim o As Object

szF = "dd.MM.yyyy"
szT = "System.DateTime"
szV = "1/1/2004"

Try
t = Type.GetType(szT)
o = t.InvokeMember( _
"Parse", _
Reflection.BindingFlags.Static _
Or Reflection.BindingFlags.InvokeMethod _
Or Reflection.BindingFlags.Public, _
Nothing, Nothing, New Object() {szV} _
)
Result = t.InvokeMember( _
"ToString", Reflection.BindingFlags.Instance _
Or Reflection.BindingFlags.InvokeMethod _
Or Reflection.BindingFlags.Public, _
Nothing, o, New Object() {szF} _
).ToString
Catch ex As InvalidCastException
'Ignore just output the unformatted data if there is an error converting
End Try


--
Armin

How to quote and why:
http://www.plig.net/nnq/nquote.html
http://www.netmeister.org/news/learn2quote.html
 
D

Dave Taylor

Armin,

Thanks! I didnt quite get the not using CreateInstance part in your first
post, although using it worked as well. The InvokeMember works nicely too.

Thanks again


Dave
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top