Help with Dynamic Casting
-
Hi I want to dynamically cast to whatever type obj is. So I want to change the Boolean part to something like obj.GetType(). obj = CType(node.SelectSingleNode(name).InnerText, Boolean)
That's not going to work since there is no way to determine what the object type is from it's XML text representation. For example:
<xml version="1.0" encoding="utf-8" ?>
<ComplexNumber>
<R>3</R>
<I>5</I>
</ComplexNumber>"3" can be anything. So you'll have to determine what that is SUPPOSED to be ahead of time before you attempt a conversion. Is that "3" really a string value containing a 3 character? Is it an Integer? Is it supposed to be a Double or a Decimal? How about a Byte? There's just no way to determine that. You have to know ahead of time what that type is before you call CType, or any other conversion method, so you can supply the appropriate type name in the CType call. One method of doing this would be to attribute your XML elements with the Type name of the value, like this:
<xml version="1.0" encoding="utf-8" ?>
<ComplexNumber>
<R typename="System.Integer">3</R>
<I typename="System.Integer">5</I>
</ComplexNumber>Retrieve the value of the typename attribute, then pass it into a conversion like this:
obj = Convert.ChangeType(xmldoc.SelectSingleNode(name).InnerText, Convert.GetTypeCode(typename))
But, you have another problem. What is defining
obj
??? Anything you return from this line of code will get boxed, if possible, by the Type that isobj
, like ifobj
was defined asObject
. This is a nice little performance hit if you're doing this many times... Dave Kreskowiak Microsoft MVP - Visual Basic -- modified at 16:05 Thursday 6th April, 2006 -
That's not going to work since there is no way to determine what the object type is from it's XML text representation. For example:
<xml version="1.0" encoding="utf-8" ?>
<ComplexNumber>
<R>3</R>
<I>5</I>
</ComplexNumber>"3" can be anything. So you'll have to determine what that is SUPPOSED to be ahead of time before you attempt a conversion. Is that "3" really a string value containing a 3 character? Is it an Integer? Is it supposed to be a Double or a Decimal? How about a Byte? There's just no way to determine that. You have to know ahead of time what that type is before you call CType, or any other conversion method, so you can supply the appropriate type name in the CType call. One method of doing this would be to attribute your XML elements with the Type name of the value, like this:
<xml version="1.0" encoding="utf-8" ?>
<ComplexNumber>
<R typename="System.Integer">3</R>
<I typename="System.Integer">5</I>
</ComplexNumber>Retrieve the value of the typename attribute, then pass it into a conversion like this:
obj = Convert.ChangeType(xmldoc.SelectSingleNode(name).InnerText, Convert.GetTypeCode(typename))
But, you have another problem. What is defining
obj
??? Anything you return from this line of code will get boxed, if possible, by the Type that isobj
, like ifobj
was defined asObject
. This is a nice little performance hit if you're doing this many times... Dave Kreskowiak Microsoft MVP - Visual Basic -- modified at 16:05 Thursday 6th April, 2006Hi Dave, Thanks for the response. My question was probably not very clear. What I want to do is not cast using the xml innertext type but the obj(name) type. I know this looks wired and I guess it is. What I’m doing (and I know when it comes to performance it is just wrong) is to map from the xml node to a property in the object using the name of the properties. Now it becomes even worse, I use reflection to get the properties names and I invoke them instead of setting the normal way. I know this is extremely inefficient in performance terms, but it is very dynamic and I like the simplicity of the code. So what happens is: 1) An XML node is read 2) Loop over the child nodes 3) Set the object (Query) properties to the node value with the same name. (Dynamically casting to the property’s type) Here is the function that does the trick.
'Builds a query from a xml node Private Function BuildQuery(ByRef node As XmlNode) As Query Try Dim obj As New Query 'Map xmlnodes to properties where the names match For Each name As String In obj.Properties If Not node.SelectSingleNode(name) Is Nothing Then 'Dynamically cast to the type of the property Dim code As Integer = CInt(Convert.GetTypeCode(obj(name))) obj(name) = Convert.ChangeType(node.SelectSingleNode(name).InnerText, code) End If Next Return obj Catch ex As Exception Throw New ApplicationException("Falied to build Databasequery object", ex) End Try End Function
On a side note I only use this rarely in the code, for reading data into object and moving data from object into file or database. These are expensive operations anyway so the overhead is not that great compared to the actual workload. That is at least the theory, but I need to do some test to check if it is correct. Thank you very much for your reply. Johan Hertz -
Hi Dave, Thanks for the response. My question was probably not very clear. What I want to do is not cast using the xml innertext type but the obj(name) type. I know this looks wired and I guess it is. What I’m doing (and I know when it comes to performance it is just wrong) is to map from the xml node to a property in the object using the name of the properties. Now it becomes even worse, I use reflection to get the properties names and I invoke them instead of setting the normal way. I know this is extremely inefficient in performance terms, but it is very dynamic and I like the simplicity of the code. So what happens is: 1) An XML node is read 2) Loop over the child nodes 3) Set the object (Query) properties to the node value with the same name. (Dynamically casting to the property’s type) Here is the function that does the trick.
'Builds a query from a xml node Private Function BuildQuery(ByRef node As XmlNode) As Query Try Dim obj As New Query 'Map xmlnodes to properties where the names match For Each name As String In obj.Properties If Not node.SelectSingleNode(name) Is Nothing Then 'Dynamically cast to the type of the property Dim code As Integer = CInt(Convert.GetTypeCode(obj(name))) obj(name) = Convert.ChangeType(node.SelectSingleNode(name).InnerText, code) End If Next Return obj Catch ex As Exception Throw New ApplicationException("Falied to build Databasequery object", ex) End Try End Function
On a side note I only use this rarely in the code, for reading data into object and moving data from object into file or database. These are expensive operations anyway so the overhead is not that great compared to the actual workload. That is at least the theory, but I need to do some test to check if it is correct. Thank you very much for your reply. Johan HertzI guess I didn't understand what you were asking the first time around. I'm happy that you found a way to do it! I, personally, have never had the need to do something like this... Dave Kreskowiak Microsoft MVP - Visual Basic
-
I guess I didn't understand what you were asking the first time around. I'm happy that you found a way to do it! I, personally, have never had the need to do something like this... Dave Kreskowiak Microsoft MVP - Visual Basic