Object Reference casting vb.net - vb.net

I have no idea on how to cast an object that type was 'Object' to a user defined class type.
I have a private instance variable:
Private studyType as Object
What i need to do is to instantiate this object from an event handling method. And no, not to instance new Object().
Basically it would look like this:
studyType = new VCEOnly()
However, I am only allowed to use the Object class subs and functions as the type was defined as Object. So i need to cast it to VCEOnly class type so i can access its subs and functions.
Basically, studyType needs to be casted from Object to VCEOnly. I am not allowed to pre-define studyType as VCEOnly when declared.

you can also use:
dim studyType as Object = new VCEOnly()
...
dim studyTypeVCE as VCEOnly = nothing
if trycast(studytype,VCEOnly) IsNot Nothing then
studyTypeVCE = DirectCast(studytype,VCEOnly)
'... do your thing
end if
the if statement checks if the object can be casted to the wanted type and if so variable of type VCEOnly will be filled in with a cast of studytype.

Use CType to cast an object from one type to another
Something like this should do it:
Dim studyType as Object
Dim studyTypeVCE as New VCEOnly
studyTypeVCE = Ctype(studyType,VCEOnly)
or you can just do this:
With CType(studyType, VCEOnly)
.SomeVCEOnlyProperty = "SomeValue"
End With

Related

Casting a string variable to a class object

Using VB.Net
I am using the CallByName() function to call certain subroutines based on a selection made by the user. The options for the subroutines come from a dropdown menu which gets it data from a table in a database. The CallByName function requires the starting class and the subroutine name as well as the method type ex: CallByName(class,subroutine,type.method). In my table I have a column for the class and a column for the subroutine. So these get read by my program as strings. I'm trying to use these variables in the function and while the subroutine string works fine, I can't seem to convert the class string into a proper class object that can be used by the CallByName function.
My code looks like:
Dim base_class as string = myReader(0)
Dim subroutine as string = myReader(1)
base_class = CType(base_class, class)
'* what I need, but doesn't work ^^^
CallByName(base_class, subroutine, CallType.Method)
How can I convert the class variable read in from the DB into something that I can use in the function?
Thanks.
Edit: The code that I ended up using that worked based on Jimi's response:
Dim t As Type = Type.GetType(base_class)
Dim obj = Activator.CreateInstance(t)
CallByName(obj, subroutine , CallType.Method)

Cast object back to original type

I have objects in a List(of BodyComponent) the BodyComponent is a baseclass, The items beeing added into the list are objects from a derived class.
Public Class Body_Cylinder
' Get the base properties
Inherits BodyComponent
' Set new properties that are only required for cylinders
Public Property Segments() As Integer
Public Property LW_Orientation() As Double End Class
Now I would like to convert the object back to it's original class Body_Cylinder So the user can enter some class specific values for the object.
But I don't know how to do this operation, I looked for some related posts but these are all written in c# of which I don't have any knowledge.
I think the answer might be here but .. can't read it Link
You could use the Enumerable.OfType- LINQ method:
Dim cylinders = bodyComponentList.OfType(Of Body_Cylinder)()
For Each cylinder In cylinders
' set the properties here '
Next
The list could contain other types which inherit from BodyComponent.
So OfType does three things:
checks whether the object is of type Body_Cylinder and
filters all out which are not of that type and
casts it to it. So you can safely use the properties in the loop.
If you already know the object, why don't you simply cast it? Either with CType or DirectCast.
Dim cylinder As Body_Cylinder = DirectCast(bodyComponentList(0), Body_Cylinder)
If you need to pre-check the type you can either use the TypeOf-
If TypeOf bodyComponentList(0) Is Body_Cylinder Then
Dim cylinder As Body_Cylinder = DirectCast(bodyComponentList(0), Body_Cylinder)
End If
or the TryCast operator:
Dim cylinder As Body_Cylinder = TryCast(bodyComponentList(0), Body_Cylinder)
If cylinder IsNot Nothing Then
' safe to use properties of Body_Cylinder '
End If

How can I get a property name for a type without the need to instantiate an object of that type?

I have a requirement where I need to have a "type safe" way of accessing property names, without actually instantiating an object to get to the property. To give an example, consider a method that takes as arguments a list of IMyObject and a string that represents a property name (a property that exists in IMyObject).
The methods implementation will take the list and access all the objects in the list using the property name passed... for some reason or another, we won't dwell on that!!
Now, I know that you can do this using an instantiated object, something like ...
Dim x as MyObject = nothing
Dim prop As PropertyInfo = PropHelper.GetProperty(Of MyObject)(Function() x.MyProperty)
Where my helper method uses reflection to get the name of the property as a string - there are numerous examples of this flying around on the web!
But I don't want to have to create this pointless object, I just want to do something like MyObject.MyProperty! Reflection allows you to iterate through a types properties and methods without declaring an object of that type... but I want to access a specific property and retrieve the string version of its name without iteration and without declaring an object of that type!
The main point here is that although I am trying to get the property name as a string... this is done at run time... at compile time, I want this to be type safe so if someone changes the property name, the compilation will break.
Can anyone help in this quest!?!
So here is a quick code-listing to demonstrate the answer that I was looking for:
Imports System.Linq.Expressions
Public Class A
Public Prop1 As String
Public Prop2 As Integer
End Class
Public Class Form1
Public Function GetPropertyNameB(Of TModel, TProperty)(ByVal [property] As Expression(Of Func(Of TModel, TProperty))) As String
Dim memberExpression As MemberExpression = DirectCast([property].Body, MemberExpression)
Return memberExpression.Member.Name
End Function
Public Sub New()
InitializeComponent()
Dim propertyName As String = GetPropertyNameB(Function(myObj As A) myObj.Prop1)
Dim propertyName2 As String = GetPropertyNameB(Function(myObj As A) myObj.Prop2)
MsgBox(propertyName & " | " & propertyName2)
End
End Sub
End Class
You may be able to pass the property in as a simple lamdba expression, and take it in the method as an expression tree. You should be able to analyze the expression tree to get the string name of the property, but it the lambda expression will fail to compile if the property name changes. Check out this page for more details:
http://msdn.microsoft.com/en-us/library/bb397951.aspx
You can make use of the NameOf function:
Dim fieldName = nameOf(MyClass.MyField)

Programatically setting an object array's object

I have
Public stack() As CTest
I want
Public stack() As Object
The latter is giving the error "Unable to cast object of type 'Object' to 'CTest'." when used:
Dim thestack As CTest() = testdatabase.getStack
Where testdatabase.getStack simply returns stack();
Public Function getStack() As Object()
Return stack
End Function
This fixes it, but it's not ideal (for me personally):
Dim thestack As Object() = testdatabase.getStack
So if I could keep the variable as-is (Public stack() As Object) and then do something along the lines of class.stack() = CTest I should be able to do Dim thestack As CTest() = testdatabase.getStack because the object array will programmatically have changed from Object to CTest.
Is this possible at all?
One way to approach this would be to write a conversion function that accepts Object and returns CTest. The function itself would cast Object to the boxed datatype, assign the value of each property on the object to the new CTest object and then return it. Something like this:
Function ConvertToCTest(o as Object) as CTest
dim unboxed as ObjectsDataType
unbox = directCast(o ObjectsDataType)
Dim result as CTest
result.Prop1 = unboxed.Prop1
result.Prop2 = unboxed.Prop2
Return result
End Function

Is there an elegant way to write this code?

I've inherited some code and it is making me cringe when I look at it. Is there more elegant way to write the following?
Dim myItem As DTO.MyBaseClass = Nothing
Dim myType As String = GetTypeString()
Select Case myType
Case Is = "Case1"
myItem = Bus.BusManager(Of DTO.MyClass1).Read()
Case Is = "Case2"
myItem = Bus.BusManager(Of DTO.MyClass2).Read()
'... etc etc for 30 lines
Is there a way to make a map from the string to the class type and then just have a line like so? Or something similar?
myItem = Bus.BusManager(Of MappingDealy(myType)).Read()
Since BusManager is a Generic, the type you pass into Of <type> must be specified at compile time. It's not like a traditional parameter that you can change at runtime.
It's unclear from the code you listed what BusManager actually does. If all it's doing is creating an instance of the Generic type, then maybe the person who created it doesn't really understand generics. Do you have the ability to rework how BusManager works, or are you limited to using it as is?
As #jmoreno mentioned, you can use reflection to create an instance of a type from a string containting the name of the type. Here's how that would work:
Imports System.Reflection
Imports System.IO
Public Class ObjectFactory
Private Shared Function CreateObjectFromAssembly(ByVal assembly As Assembly, ByVal typeName As String) As Object
' resolve the type
Dim targetType As Type = assembly.GetType(typeName)
If targetType Is Nothing Then
Throw New ArgumentException("Can't load type " + typeName)
End If
' get the default constructor and instantiate
Dim types(-1) As Type
Dim info As ConstructorInfo = targetType.GetConstructor(types)
Dim targetObject As Object = info.Invoke(Nothing)
If targetObject Is Nothing Then
Throw New ArgumentException("Can't instantiate type " + typeName)
End If
Return targetObject
End Function
Public Shared Function CreateObject(ByVal typeName As String) As Object
Return CreateObjectFromAssembly(Assembly.GetExecutingAssembly, typeName)
End Function
Public Shared Function CreateObject(ByVal typeName As String, ByVal assemblyFileName As String) As Object
Dim assemblyFileInfo = New FileInfo(assemblyFileName)
If assemblyFileInfo.Exists Then
Return CreateObjectFromAssembly(Reflection.Assembly.LoadFrom(assemblyFileName), typeName)
Else
Throw New ArgumentException(assemblyFileName + " cannot be found.")
End If
End Function
End Class
In a production app, I'd probably set the return type for all of these methods to my base class or interface. Just make sure you pass in the full typeName including the Namespace.
With that factory class in place, then the elegant version of your code would look something like this:
Dim myItem as DTO.MyBaseClass = ObjectFactory.CreateObject("DTO." & GetTypeString())
First of all, never use Case Is = and never initialize to Nothing. So a quick one would be:
Dim myItem As DTO.MyBaseClass
Select Case GetTypeString()
Case "Case1"
myItem = Bus.BusManager(Of DTO.MyClass1).Read()
' etc etc
But since you're using templating, there's really no way to map it unless you want to use reflection, which is horribly inefficient at the expense of slightly cleaner and shorter code. You could also add an Imports DTO to save on 124 characters, and also Bus to save on another 120 characters.
Without seeing more of the code I would recommend use an Enumeration on my Case Statement to prevent minor bugs from appearing.
You could then either use a Factory Method to process the data based on the Enumeration.