Assign a type to an object at runtime in vb.net or c# - vb.net

I have an object, o, and a type, T. I'd like to use reflection to change object o to type T at runtime without instantiating it.
The equivalent at compile time would be:
Dim p as Point = Nothing
I know how to use Activator.CreateInstance to create an instance at run time that is equivalent to:
Dim p as New Point()
But i don't want to do this. I have no knowledge of the type's constructor parameters and some types don't have a parameterless constructor. eg. Font.
So, to sum up, I'd like a way of performing the equivalent of:
Dim o as T = Nothing
In case you're wondering why I'm doing this, it's because I'm using a PropertyGrid on a form to edit types. If this is the first time for editing, say, a Font, then passing an uninitialised Font to the PropertyGrid makes the grid display the default values.
Cheers.
ETA:
I tried 'o = GetUninitializedObject(T)', but the PropertyGrid either wants a properly initialised object or an object, with a defined type, set to nothing.
I've actually solved my particular problem here:
how-to-use-the-property-grid-in-a-form-to-edit-any-type
, but i'd still be interested to know how to assign a type at run-time without the use of a wrapper class (which I was lucky enough to be using).

The closest thing would be to set o to default(T). Assuming the default is not Nothing (null), you'll get a default value such as Rectangle.Empty or 0 (int).
Nothing (null) doesn't have a type associated with it, so if o as object, (T) Nothing won't help.

Related

Accessing Dynamic Dims

I am creating what I believe is the way to create dynamic dims e.g.
Dim browser(DataGridView1.Rows(e.RowIndex).Cells(0).Value)
which basically is creating a something like Dim browser(1)
However I am trying to write a test button to call this browser by using:
browser1.load("http://google.com")
and I have even tried
browser(1).load("http://google.com"
I get the browser part underlined.
What is the correct way to reference them?
I'm not sure what the end goal is, but this construct:
Dim browser(1)
Is effectively the same as:
Dim browser(1) as Object
i.e. it's creating an array of Object of length 2, which is fine in that it can hold anything but makes your life pointlessly hard because you then have to cast the contents every time you want to do something with them; it's bad enough storing a single thing (such as a web browser widget) as an Object:
'this is bad
Dim browser as Object = New WebBrowserWidget
Because you have to cast it every time you use it (when Option Strict is On, which is really the only way you should ever program)
DirectCast(browser, webBrowserWidget).Load("http://google.com)
But to then add the indirection of storing it in an array:
'this is worse
Dim browser(1) as Object
browser(0) = New WebBrowserWidget
browser(1) = New WebBrowserWidget
And casting them to use them:
DirectCast(browser(0), webBrowserWidget).Load("http://google.com)
Just give these things a proper type when you declare them, or use type inference by providing something on the right hand side of an = that is a particular type:
'infer the type from the right hand side
Dim browser = New WebBrowserWidget
'or declare, give a type and create a new instance to assign to it
Dim browser as New WebBrowserWidget
Then it's a lot easier to use it, because Intellisense will know it's a browser and offer you help with the methods and properties, such as Load:
browser.Load("http://google.com")
If you code with Option Strict Off then you can store things in an object and just cross your fingers and hope you get everything right when youre coding, but it's like writing javascript - fumbling round eyes closed not knowing whether you got it right til it blows up at runtime:
Dim x as Object = New WebBrowserWidget
x.Load(...) 'don't get any intelllisense for this, but it'll work at runtime
x.Laod(...) 'dont get any compiler error even though this is a typo - it'll just explode at runtime

What exactly are parentheses around an object reference doing in VB.NET?

I have some procedures that take Control object references as a parameter.
I have a bunch of Controls throughout my project of varying derived types such as Button, TextBox, PictureBox, ListBox, etc.
I was calling the procedure and passing the reference as normal:
Procedure(controlRef)
I changed some of the Warning Notifications in my project configuration. I'm guessing it was changing the Implicit Conversion Notification from 'None' to 'Warning' that caused warnings similar to the following to appear everywhere these procedures were called:
"Implicit conversion from 'Control' to 'Button' in copying the value of 'ByRef' parameter 'parControl' back to the matching argument."
This makes sense, I'm doing an Implicit Conversion, but hang on a second, I'm passing a Button in to a Control parameter, not a Control to a Button like it says, I'm slightly confused what's happening here.
Anyway, I take a look at the "Show potential fixes" and there is no fix suggestion, only Suppress or Configure options, okay. So I do a explicit cast using DirectCast(controlRef, Control) to see if that'll remove the warning on Implicit Conversion, which it does, but it gets replaced by a Redundant Cast warning, again, this makes sense. So I remove the cast using the potential fixes and the argument in the procedure call is left with parentheses around it and no more warnings.
Procedure((controlRef))
What is going on here exactly?
Since the signature for Procedure is Sub Procedure(ByRef param As Control) and you're passing a Button to the method, the compiler is correctly warning you about an implicit conversion.
Imagine that this were the definition of Procedure:
Sub Procedure(ByRef param As Control)
param = New Label()
End Sub
And if you called it this way:
Dim button = New Button()
Procedure(button)
Then you're effectively calling this code:
Dim button As Button = New Button()
button = New Label()
Hence the compiler warning.
If you change the signature to Sub Procedure(ByVal param As Control) then there is no possibility of assignment back to the calling variable and the warning will go away.
The use of the extra parenthesis forces the call to be ByVal instead of ByRef. See https://learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/procedures/how-to-force-an-argument-to-be-passed-by-value
This is not an answer to the question but it may be a solution to the actual problem. It also requires significant code, so I decided an answer was the best option.
One has to wonder why you have declared that parameter ByRef in the first place. Many people do so when it is not required because, as in VB6, they think that it will prevent an object being copied. That is not the case because reference type objects, i.e. class instances, don't get copied when passed by value anyway. That's the whole point of reference types, i.e. the value of a variable is a reference, not an object, so passing by value only copies the reference, not the object. If you are not assigning anything to that parameter inside the method then it should be declared ByVal.
If you are assigning to the parameter inside the method then the solution is to declare the method to be generic. That way, the parameter won't be Control but will actually be the type you pass in. In its simplest form, that would be:
Private Sub Procedure(Of T)(ByRef control As T)
'...
End Sub
That's probably not enough though, because that would allow you to pass any object as an argument. To restrict the method to only accept controls:
Private Sub Procedure(Of TControl As Control)(ByRef control As TControl)
'...
End Sub
Now you will only be able to pass a control to the method but, inside the method, the parameter will be treated as the actual type of the argument you passed, e.g. if you pass a Button then TControl is fixed to be Button. If you need to create a control of the appropriate type inside the method then you need another restriction too, which enables you to assume a parameterless constructor, e.g.
Private Sub Procedure(Of TControl As {New, Control})(ByRef control As TControl)
control = New TControl With {.Location = New Point(100, 100),
.Size = New Size(50, 25)}
'...
End Sub
That code means that, inside the method, you know that the type of the parameter is Control or derived from that type and that you can create new instances by invoking a parameterless constructor.

Sender.Gettype from multiple handles

I have code that handles multiple events. FYI - I use Devexpress Components. I have two items, a Lookupedit and a GridLookupEdit, that are handled by the same code. I am trying to do something like the following:
Dim type = sender.GetType()
Select Case DirectCast(sender, Type).Name
Case "mgrLUE"
log("View metrics for manager: " & mgrLUE.Properties.GetDisplayText(mgrLUE.EditValue), Me.Name)
Case "sectLUE"
log("View metrics for section: " & sectGLUE.Properties.GetDisplayText(sectGLUE.EditValue), Me.Name)
End Select
I am getting errors at the select case line. I cant figure out how to dynamically get the type to be able to direct cast to it. The types will be DevExpress.XtraEditors.GridLookUpEdit and DevExpress.XtraEditors.LookUpEdit in this case. I have tried searching for a solution, but everything I have tried is failing.
Thank you for the help.
Casting can't be done dynamically because its sole purpose is to let the compiler know that you expect an object to be of a certain type. This is necessary so that the compiler knows what members the object contains when you try to access it.
I should mention that VB.NET has a feature called late binding, which allows you to access members of a type wrapped in an Object by looking up if the member you're trying to access exists at runtime. Using late binding, however, is not recommended as it is very easy to make mistakes and break your code.
Now, as for your problem: Casting can be done if an object is of a certain type, or if it inherits from that type. Since I'm guessing what you're using are controls (that you've placed on your form) they all should inherit from System.Windows.Forms.Control, thus you can cast them to that which contains the base property Name:
Select Case DirectCast(sender, Control).Name

VBA assigning new object to variable?

I'm trying create new object from a module class in VBA, and I have a small diffcult. Two line of assigning code, look like the same, but result is different.
I got a error message:
After that, I switch to use (1) instead of (2), error was fixed.
But I dont understand; Why do they have this difference?
Dim declares a variable, Set instantiates it.
So, it's a good practice to always have Dim before Set.
If you do not use Dim to declare the specific type of a variable you may subsequently change the variable to another type, for example after;
set aosh = new AOSHRatioQuery
You could mutate the variable to a string;
aosh = "A pint of milk"
As the sendAsyncRequest method expects a AOSHRatioQuery as its 2nd argument & the VBA compiler knows that it cannot guarantee that the aosh variable will actually contain an instance of that type, type safety is violated & the Type Mismatch error is raised to prevent sendAsyncRequest from receiving garbage it cannot interpret.
Explicitly typing with Dim aosh as new AOSHRatioQuery tells the compiler that aosh is guaranteed to always be AOSHRatioQuery instance or Nothing (attempting to assign it to another type will raise an error) so it can be passed safely.
In VBA, you have to declare variables using the Dim keyword, and then defining their data types with the As keyword. That's just how its syntax works. As a general form:
Dim <variableName> As <dataType>

Is it possible to declare a local/class instance member reference variable in VB.net to read/update same object referred by another variable

In C++, it is possible to do:
int x;
int& foo = x;
// foo is now a reference to x so this sets x to 56
foo = 56;
But is an equivalent possible in Visual Basic .net (VB.net)?
I am aware of the ByRef term in VB.net but I have only seen (and by extensive research) this in passing parameters by reference to functions/subroutines, so that the function modifies the same variable declared by the calling code.
But I haven't seen ByRef used to declare variables (as class members or local variables). I have tried to use ByRef to do such a declaration but I get compiler errors for each ordering of the declaration I try.
The reason why I want to do this is because I want a class instance to be able to refer to a variable declared in another class instance.
Specifically, I am working on some existing VB.net code where program logic is mixed up with UI logic in VB.net form classes. I want to separate the program logic out of the form code so that it can be more easily reused. To do this I need the program logic code to be able to 'talk' to the form code so I need access to its variables.
I am using Visual Studio 2010 Express with VB.net and would prefer to remain within this environment even though I am aware that full Visual Studio has extended capabilities.
Pointers exist but they're called object references
(Now other posters, please don't quibble with me about the actual differences here. I am talking about the high level task the OP wants to accomplish)
Obviously you can't do literally what you've said - that is, surgically manipulate one member. But if you have control of the code, you can do almost as well. And from what you describe is your problem, this method will be much better, as you can pass references to an object that has many members you wish to update, instead of having to pass many individual pointers.
First define a class:
Class MyScreenValues
' Properties will work... using public fields for brevity
Public TextBox1Value as String
Public SpinControl1Value as Integer
public CheckBox1Value as Boolean
End Class
Now the equivalent of the code you posted:
Dim x as new MyScreenValues 'int x;
dim foo as MyScreenValues = x 'int& foo = x;
'// c++: foo is now a reference to x so this sets x to 56
'// .net: foo is now a reference to x so this sets x.SpinControl1Value to 56
foo.SpinControl1Value = 56;
If what you're doing is trying to pass pointers to, say, every control on your form's value to a sub, like so:
Button1_Click(...
Dim MyObject as new BusinessObject
MyObject.DoSubmit(TextBox1.Text, SpinButton1.Value, CheckBox1.Checked)
You can use the method provided by superbDeveloper, and use the ByRef keyword on the definition of the DoSubmit Sub:
Public Sub DoSubmit(ByRef Name as String, ByRef Age as Integer, ByRef Employed as boolean)
... business logic...
However this just gives you a 2-layer separation. Look into MVP, MVC, etc - however consider submitting the entire view worth of data. It's a lot of research you you may settle with what you have now. For example your business logic will be firing events on the form as it changes the form values (well, actually, they won't fire until the sub exits, due to the way VB deals with byref properties [=temp variable], but it needs to be considered).
You can also map an object's properties to a Form's properties with other libraries. Check out VALUE INJECTOR on the web. It can take a webform/winform and maybe even a WPF form and map the control values to and from an object you have predefined. Excellent for complete separation.
Hi well not sure about VB.NET but I know how do it in C#, therefore I did the solution in C# and then i used a C# to VB.NET convertor to get the VB.NET code. maybe it might help you:
http://www.developerfusion.com/tools/convert/csharp-to-vb/
C# Code
protected void TestFoo()
{
string strFooA = string.Empty;
GetFoo(ref strFooA);
Response.Write(strFooA);
}
private void GetFoo(ref string strFooA)
{
strFooA = "FooA";
}
VB.NET converted
Protected Sub TestFoo()
Dim strFooA As String = String.Empty
GetFoo(strFooA)
Response.Write(strFooA)
End Sub
Private Sub GetFoo(ByRef strFooA As String)
strFooA = "FooA"
End Sub
Pointers don't exist in the .NET framework like they do in C/C++, so you won't be able to directly achieve what you want.
There are some possible solutions on this SO page
See #NathanW answer on there:
If you are using VB the only thing that is really close to a pointer is a IntPtr. If you have access to C# you can use unsafe C# code to do pointer work.
In Addition
If you want to be able to use references then you can achieve this by using a class:
Private Class RefClass
Public x As Integer
End Class
Then you can reference one from the other:
Dim bar As New RefClass
Dim foo As RefClass = bar
bar.x = 45
Debug.WriteLine(bar.x) 'outputs 45
Debug.WriteLine(foo.x) 'outputs 45
You may already know enough to get the job done from the info at http://www.dreamincode.net/forums/topic/135354-reference-types-value-types-byval-byref/ ; however, your remark "ByRef is not required in declaration of local variables (and possibly class variables)" left me wondering if there's some confusion here.
For starters, the C++ example above, int x; int& foo = x; confuses what is meant by a "reference". My C++ isn't very strong, but, semantically speaking, I believe this C++ reference operates more like an aliasing mechanism. In VB (and C#) a reference operates like an identification code that locates an instance of a class in memory. Neither VB or C# has anything like the C++ reference type.
By now, you probably already know you can pass in your Form as a ByVal parameter, and change its properties and fields without problem. (ByVal is the default in VB.NET, so you don't even need to use it - in VB6 ByRef was the default.) If you're happy enough, you can skip the rest. But, yeah, in the case of .NET Reference variables, assuming:
Dim objA as New MyClass()
Dim objB as MyClass = objA
Then objA and objB both reference the very same instance of MyClass. You can modify via objA and objB, and you can read back from either objA or objB, because they each affect the very same instance. You can pass either objA or objB into some subroutine Foo with parameter objC As Object passed ByVal (i.e. Sub Foo(ByVal objC As Object) ) and Foo can then modify that same instance too.
The ByRef of VB and the ref of C# indicate a modifiable parameter, which means some "identification code" reference is passed instead of a value. Yet this ByVal vs. ByRef thing is clear as mud because in .NET there is a distinction made between "Value" types and "Reference" types that confuses many on whether a ByRef or ref is needed or not.
Visual Basic and C# dichotomizes variables (and data types) into two species: the "Value" (or "Structure"), and the "Reference" (or "Class").
The "Value" type means an actual collection of bits that represents an Integer, or a Boolean, or even a bitmap, or some other kind of object. In old school parlance, this is the "image" of the instantiation of an object. It is the state space of the object. It is what makes an object essentially itself, independent of where in memory it may be.
The "Reference" type means a code (which might look like an integer or a pointer) that somehow indicates the data type of the object and where in memory it resides. The computer will interpret a "Reference" to obtain the actual image of the object (i.e. its "Value").
When a "Value" parameter is passed ByVal, that means a new object is created that is in the identical image of the original expression being passed, and it is upon this copy that the function or method operates. The original image of the "Value" cannot be affected.
When a "Value" parameter is passed ByRef, that means a new "Reference" variable is created, and that "Reference" variable will contain the information that will interpret back to the image of the original "Value". Now the original image of the "Value" can be changed.
When a "Reference" parameter is passed ByVal, its "identification code", which gets interpreted back to the actual image of the object, gets copied. It is upon this copy of the code that the function or subroutine or method operates. This copy still points to the actual image of the object. Which means that an object of a Reference variable that is passed by ByVal can still have its image (i.e. its "Value") changed. However, the code of the original "Reference" itself cannot be changed.
(Note that the String type is an odd duck: It will behave as if it were a "Value" parameter even though it is in fact a "Reference" type. Hence a String passed ByVal will not be affected in the same way any other class would. Actually, String is an example of an immutable type - which means that steps are taken to prevent changes to its "Value".)
When a "Reference" parameter is passed ByRef, one now has created a new "Reference" object that points to the original "Reference" object (that, in turn, points to the "Value" of some other object via its "identification code"). The use of ByRef on a "Reference" allows one to modify (or create anew) the "identification code" of the original "Reference" object being passed as a parameter. A function or subroutine or method that performs a swap operation will use ByRef on "Reference" parameters.