Need help converting C# to vb. "array initializer is missing 1 elements" - c#

I am trying to convet the following code from C# to Vb using 3.5 framework.
Here is the code in C# that I am having trouble with.
MethodInfo mi = typeof(Page).GetMethod("LoadControl", new Type[2] { typeof(Type), typeof(object[]) });
I thought it would be like this in VB;
Dim mi As MethodInfo = GetType(Page).GetMethod("LoadControl", New Type(2) {GetType(Type), GetType(Object())})
but I am getting the following error "array initializer is missing 1 elements"
The other line that I am having trouble with and getting the same error is
control = (Control) mi.Invoke(this.Page, new object[2] { ucType, null });
I tried this in vb but it does not work.
control = DirectCast(mi.Invoke(Me.Page, New Object(2) {ucType, Nothing}), Control)
ucType is defined as follows
Dim ucType As Type = Type.[GetType](typeName(1), True, True)
Any help would be greatly appreciated.

VB.Net arrays are 0-based, but declared using the highest-index rather than the number of items. So a 10-item array, indexed 0..9, is declared as Item(9).
With that said, the real solution to your problem is to let the compiler figure out the array length, like so:
Dim mi As MethodInfo = GetType(Page).GetMethod("LoadControl", New Type() {GetType(Type), GetType(Object())})

In VB.NET the array declaration takes the upper bound of the array, not the length like C# does (kind of silly if you ask me). Because of this, you need to reduce the number passed into your array declarations by 1 (since arrays are zero-based).

For the first line you need to change new Type(2) into New Type(1).
Dim mi As MethodInfo = GetType(Page).GetMethod("LoadControl", New Type(1) {GetType(Type), GetType(Object())})
In VB.Net the number specified in the array initializer is the highest accessible index vs. the length. The second line you mentioned has the same problem and solution.

VB uses the upper bound as the argument for arrays.
new byte[X]
new byte(X) 'wrong, 1 more element
new byte(X-1) 'correct, kinda confusing
new byte(0 to X-1) 'correct, less confusing
I suggest using the (0 to X-1) style, because it's a lot clearer. It was a lot more important in the vb6 days when array(X) could mean 0 to X or 1 to X depending on the context.

It will be like this -
Dim mi As MethodInfo = GetType(Page).GetMethod("LoadControl", New Type(1) {GetType(Type), GetType(Object())})
The other one will be -
control = DirectCast(mi.Invoke(Me.Page, New Object(1) {ucType, Nothing}), Control)

There is an online version available at http://converter.telerik.com which converts
C# to VB and vice versa.

Related

Cannot compare object from Arraylist to the actual object

I'm trying to select a random user control within an array list. I get the index of the array but it tells me it cannot simply convert int to UserControl. Anyone knows what I did wrong?
ArrayList notiList = new ArrayList();
int count = 0;
int i;
public MainPage()
{
this.InitializeComponent();
foreach (NotiObject noti in itemsPanel.Children.Where(c => c is NotiObject))
{
notiList.Add(noti);
System.Diagnostics.Debug.WriteLine(noti);
}
i = new Random().Next(0, notiList.Count);
}
void sendNotification()
{
NotiObject randomNoti = notiList.IndexOf(i);
}
As Dai has hinted, ArrayList is a particularly old thing, from back in the days when .net was relatively new and didn't have the incredibly useful feature known as generics.
The manual page for ArrayList says this (my emphasis):
Important
We don't recommend that you use the ArrayList class for new development.
Instead, we recommend that you use the generic List class.
Even the manufacturer is saying "don't use this product"
The big problem with ArrayList is that because it wants to be able to store anything, it holds its contents in an object array
This means you can put two completely unrelated things in next to each other, you have to inspect the type of them if you do, and you always have to cast to turn the object back into what you want
notiList.Add(123); //whoops, that's not a NotiObject
foreach(var o in notiList)
var n = (NotiObject)notiList[0]; //whoops, that's a crash
}
So, working with it is pretty wearisome, particularly the part where you have to cast all the time.. This gets boring very quickly:
object o = "hello";
object p = "world";
object q = (string)o + (string)p;
object r = ((string)q).Substring(3).IndexOf((stribg)p);
r = (int)r + ((int)r)/2;
Storing everything in an object can be done, but look at what a mess it is. You'd have to start putting the type name into the variable name just to help remember that r was an int, and q was a string - Hungarian notation's another relic of the past.
When you put things in an ArrayList, this is what you're doing; storing them in object
So generics were invented and List was invented. A list that can be custom made to store a single type of objects like a string, int or NotiObject
var nums = new List<int>();
nums.Add(123); //works
var notiList = new List<NotiObject>();
notiList.Add(123); //compiler refuses this one
Now I've said all that, it's possible to answer your question. This code doesn't make sense:
NotiObject randomNoti = notiList.IndexOf(i);
i is an integer. IndexOf is a method that finds the numeric index of an item in the list. If the list was "a","b","c" and you asked for IndexOf("b") the result is 1 because b is at the second index, and indexing starts from 0.
IndexOf is not "get me the object at index blahblah", it's "tell me the index of this object blahblah"
The code doesn't make sense because you've passed an integer in and the list stores NotiObject. IndexOf will never find an integer in a list of NotiObject. This was the first mistake. You were allowed to make it because ArrayList stores everything as objects so you're allowed to pass an integer into IndexOf even if there are no integers in the list
IndexOf returns an integer. You cannot assign an integer to a variable of type NotiObject. This is the thing the compiler is complaining about
Even if you form the code correctly, you still have to cast:
NotiObject randomNoti = (NotiObject)notiList[i];
It's all very wearisome and if you persist with ArrayList probably not the last mistake you'll make with it either
If you used a List<NotiObject> you wouldn't have been allowed to pass an integer to IndexOf; the compiler would have stopped you which would hopefully then have made you assess IndexOf in the docs, and see that it's for finding the int index from the object, not the object at int index
You'd write code like:
List<NotiObject> notiList = new List<NotiList>();
...
NotiObject randomNoti = notiList[i];
without the cast. If you want to read more into why there is no cast, check out some introductory articles to generics. In a nutshell generics (any time you see something like <T> or <TBlahBlah>) allow you to specify something like a template code skeleton that the compiler uses to create code for you; code that substitutes the for the kind of object you want to work with. There isn't any casting any more because the compiler will write a whole List class that dedicatedly only works with NotiObjects

VB.NET equivalent of C# object initializer of an anonymous type

I'm not experienced with advanced features of .NET type system. I cannot find out of what type is zz (what can be written instead of var. Or is var the best choice here?)
string foo = "Bar";
int cool = 2;
var zz = new { foo, cool }; // Watches show this is Anonymous Type
but most importantly, how the equivalent can be achieved in VB.NET code (this is what I actually need).
Dim Foo As String = "Bar"
Dim Cool As Integer = 2
Dim zz = {Foo, Cool} 'This is not an equivalent of above, I'm getting an array
I have searched several C# sources, used code watches and learned about how zz looks internally but I'm unable to make next step.
(The purpose of my effort is something like this in VB.NET.)
Your code would not even compile with OPTION STRICT set to ON which is highly recommended. No type can be derived from String + Int32. It would compile if you want an Object():
Dim zz As Object() = {Foo, Cool}
But you want to create an anonymous type, use New With:
Dim zz = New With {Foo, Cool}
http://msdn.microsoft.com/en-us/library/bb385125.aspx
With .NET 4.7 and Visual Basic 2017 you can also use ValueTuples with names:
Dim zz = (FooName:=foo, CoolName:=cool)
Now you can access the tuple items by name:
int cool = zz.CoolName;
https://learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/data-types/tuples

C# to VB.NET array initialization

In C#, I can declare an array variable like this
object[] Parameters;
and initialize it like this:
Parameters = new object[20];
In Visual Basic, declaring and initializing an array is easy:
Dim Parameters(19) As Object
Dim Parameters As Object(19) ' Alternative syntax
How would I initialize an array variable that has already been declared in VB.NET?
Parameters = New Object(19) doesn't work.
For example, how would I translate the following to VB.NET?
int value = 20;
object[] Parameters;
if (value > 10)
{
Parameters = new Object[20];
}
Basically the same Visual Basic code as the others, but I'd use the opportunity to add a bit of style:
Dim value = 20 ' Type inference, like "var" in C#
Dim parameters() As Object ' Could also be "parameters As Object()"
If value > 10 Then
parameters = New Object(19) {} ' That's right, Visual Basic uses the maximum index
End If ' instead of the number of elements.
Local variables (parameters) should start with a lowercase letter. It's an established convention and it helps to get correct syntax highlighting in Stack Overflow (this also applies to the original C# code).
So, why are the braces {} required in Visual Basic? In Visual Basic, both method calls and array access use parenthesis (...). Thus, New X(4) could mean:
Create a new object of type X and pass 4 to the constructor,
Create a 5-element [sic] array of X.
To distinguish the two cases, you use the array initializer syntax in the second case. Usually, the braces contain actual values:
myArray = New Integer() {1, 2, 3}
Dim value As Integer = 20
Dim Parameters() as object
If value > 10 then
Parameters = new Object(value - 1){}
end if
If you are lazy like me you could use an online converter which yields:
Dim value As Integer = 20
Dim Parameters As Object()
If value > 10 Then
Parameters = New [Object](19) {}
End If
And if you are not like me and want to learn VB.NET head over to the documentation of the VB.NET syntax and start reading.

C# Defining the Length of a Generic created using Reflection

I have code like this:
Type typPrecise = MostPrecise(typeof(int), typeof(double));//Evaluates to double
var varGeneric = typeof(Number<>);
var varSpecific = varGeneric.MakeGenericType(typPrecise);
dynamic nmNumber = Activator.CreateInstance(varSpecific);
The nmNumber is of dynamic type and essentially produces a Generic Number. How do I then specify the number of items in Number.
I basically want to accomplish this but by using the dynamic code above:
Number<typPrecise> whatever = new Number<typPrecise>(10);
An answer using 4.0 concepts is welcome.
Call the overload of Activator.CreateInstance that accepts constructor arguments:
dynamic nmNumber = Activator.CreateInstance(varSpecific, new object[] { 10 });
Incidentally note that the List<T>(int) constructor sets the initial capacity of the List, not the initial number of items (Count). The initial Count is always 0.

Why do we have to call a constructor for each element in an Array?

This seems like a basic question, but it's still bugging me.
Why doesn't
MyObject [] myobject = new MyObject [10];
allocate 10 objects? Why do we have to call new on each individual object?
myobject [0] = new MyObject();
:::
myobject [9] = new MyObject();
Or am I just making a silly mistake? :)
As far as I am aware, you arent creating 10 objects in the array, you are creating an array with 10 spaces for objects of type "My Object", null is a perfectly acceptable state for an item within the array though.
You're calling the array constructor, which creates an array, not the object constructor ten times.
What constructor on the element type would you like to call? There's no way to provide any parameters as it is. The only constructors being called implicitly are value types (structs) like integers and doubles.
What if the element constructor fails? It could throw any exception. Should you get an half initialized array, or no array at all? Should the exception bubble or be hidden?
What if the element constructor is just very very slow. Add a Thread.Sleep() and the code that calls you would basically hang. How would you debug that?
And my last thought, why are you even using arrays when there's List<T>? =)
It's because it only allocates references to MyObject, not the object itself. That's the case with every non-primitive type in languages like C# or Java.
You could also use the following declaration style (not particularly useful in the following example, I would recommend a for loop instead)
MyObject[] myObject
= new MyObject[]
{ new MyObject(),
new MyObject(),
new MyObject(),
new MyObject(),
new MyObject(),
new MyObject(),
new MyObject(),
new MyObject(),
new MyObject(),
new MyObject()
};
however, in this case it could be easier to type.
int[] myInts = new int[]{ 10,34,13,43,55,2,0,23,6,23 };
That's exactly how it should be done.
For example:
MyObject[] myObject = new MyObject[10]; // creates 10 null references
for (int i=0;i<myobject.Length;i++)
myobject[i] = new MyObject();
Because all you have created is an array with 10 spaces that will contain your MyObject object instances. When will you put those in and in what state, it's up to you.
Looks like your talking about C# from the syntax.
More or less, in the CLR/.NET framework, an array is an array which contain's object's of type MyObject. Unlike C/C++, where an array is an array of objects of type MyObject.
i.e. C# array's are simply container's, conceptually they are they are distinct from the object's they hold. C/C++ (native memory), your pretty much cheating and forgo'ng the formality of having clear seporation of duties... your array is essentially the object it contains....

Categories

Resources