Unable to understand array behaviour - c#

Try:
Array[] UserInformation;
UserInformation[0] = "Test";
but i get a error Cannot implicitly convert string to System.Array
But this works:
string[] asp;
asp[0] = "ram";
I don't want to use string[] or int[] because I have to assign different data types in each index.
If its not the right way to add items to an array please suggest the correct way?

Array is a type that exists in the BCL - you are looking for an object array, which you also need to initialize:
object[] UserInformation = new object[10];
UserInformation[0] = "Test";

Array[] UserInformation;
This declares UserInformation as an array of arrays... A string is not an array.

You'll need to create an array of "object", since everything in C# inherits from that base class.
object[] anArray = new object[];

Related

Convert double[] to System.array c#

I'm using a visual basic library and one of the methods I'm using calls for a System.Array to be passed into it.
I've tried using "double[]" and "Object[]" when declaring my array however those will not pass.
I'm not sure how to convert/declare a "System.Array".
Object[] filledVals = new Object[9];
xyz.getDoubleArray("NumVoids", out filledVals); //where .getDoubleArray(string, System.Array)
Simply declare it as System.Array:
Array filledVals;
xyz.getDoubleArray("NumVoids", out filledVals);
Since it is an out parameter, you don't need to initialize it as it must be initialized by getDoubleArray.
To convert it to a double[] you can use this:
double[] result = filledVals.OfType<double>().ToArray();
You can use LINQ:
System.Array result;
xyz.getDoubleArray("NumVoids", out result);
var filledVals = result.OfType<double>().ToArray();

Why does param object[] array become jagged if you pass an int[] array into it?

As I was experimenting with params, I noticed the MS documentation says if you pass an array of int as a method parameter that has a signature of params object[] myParam, it will become a multi-dimensional array. But I noticed if you pass an array of objects[] or strings[] it does not. This seems like it would be a headache to work with, as you have to check for multi-dim arrays.
See MSDN link
Example:
public static void UsingParams(params object[] myParam)
{
//Code to return myParam
}
//myParam[0][0] = {1, 2}, multi-dimensional
int[] myIntArray = {1, 2};
UsingParams(myIntArray);
//myParam[0] = {"1", "2"}, single-dimensional
string[] myStrArray = {"1", "2"};
UsingParams(myStrArray);
Why does this occur?
Whenever you have a params parameter the compiler will attempt to accept an array representing all of the values for the params argument, if the parameter at the position in question is valid in that context. If it's not, then it tries to treat it as one item in the array of params values, rather than as the whole array. If it can't do that either then it will fail to compile.
In your second example a string[] can be implicitly converted to an object[], so it is passed as the entire list of parameters. This implicit conversion is valid because of array covariance.
In your first example the int[] cannot be implicitly converted to an object[] (array covariance is limited to reference types), so it is treated as one value in the array. An int[] can be implicitly converted to object, so what is passed is an object array containing an int[] as its only item. Note that an array with another array as an item is dramatically different from a multi-dimensional array.
C# is trying to figure out, when you only pass one value to a params argument, whether you mean for that value to be the array represented by the argument, or whether you're passing it the first argument of a larger array.
If you remove the params keyword, you'll see that int[] cannot be converted directly into an object[] (due to int being a non-reference type):
So C# figures it must just be the first of your params that you're passing in, rather than the entire array. It converts your code to this:
int[] myIntArray = {1, 2};
UsingParams(new object[]{myIntArray});
Basically your method signature is taking one or more objects and consolidating them into an array called myParam.
If multiple objects are passed individually, such as the call UsingParams(1, "hello", ...), they'll automatically be converted to the object[] array. This is a compiler trick / syntactic sugar.
If the object being passed is not an object[] array or list of individual objects, it will become the first argument of your array. In other words, if you pass an int[] then your myParam will be an array, the first element of which is an array also, making it a jagged array. This is because int[] is an object and the compiler isn't smart enough to figure out what you're doing and makes it the sole element of the object[] array. There is no implicit cast from int[] to object[] and this is why it doesn't happen.
The only time you can pass an array that will be populated as you'd expect is when that array type is object[], such as new object[] { 1, "hello", ... } or the array type is covariant. In this case, a string[] array is covariant and can be implicitly cast to an object[] while an int[] cannot.
In summary:
UsingParams(1, "hello") = good
UsingParams(new object[] { 1, "hello" }) = good
UsingParams(new string[] { "hi", "hello" }) = good (due to array covariance)
UsingParams(new int[] { 1, 2 }) = bad (no array covariance), will be a jagged array
Further reading on array covariance rules which also cites: "Array covariance specifically does not extend to arrays of value-types. For example, no conversion exists that permits an int[] to be treated as an object[]."

Why can't I convert an object (which is really object[]) to string[]?

I have a field that is of type 'object'. When I inspect it within the Watch window of visual studio I see its Object[] and when I drill into the elements I see each element is a string.
But when I try to cast this to a String[] I get this error:
Cannot cast 'MyObject' (which has an actual type of 'object[]') to 'string[]' string[]
Any reason why I can't do this cast? What is the best way to convert this object to a string array?
This is a particularly confusing feature of C#. Here's the deal.
Throughout this discussion we assume that the element type of an array is a reference type, not a value type.
C# supports unsafe array covariance. That means that if you have an array of string, you can convert it to an array of object, because a string can be converted to an object:
string[] a1 = { "hello", "goodbye" };
object[] a2 = a1; // Legal
If you then try to get an element out of a2, it works:
object o3 = a2[0];
That's legal because a2[0] is really a1[0], which is a string, which is convertible to object.
However, if you attempt to write to the array then you'll get an error at runtime:
a2[0] = new object();
This fails at runtime because a2 is really an array of strings, and you can't put a non-string into an array of strings.
So C# is already horribly broken; it is possible to write a program that compiles and looks normal but suddenly crashes with a type exception at runtime because you tried to put an object into an array of objects that is not actually an array of objects.
The feature you want is even more broken than that, and thank goodness C# does not support it. The feature you want is:
object[] a4 = { "Hello" };
string[] a5 = a4;
That would be unsafe array contravariance. It breaks horribly like this:
a4[0] = new Customer(); // Perfectly legal
string s6 = a5[0];
And now we just copied a Customer into a variable of type string.
You should avoid any kind of array covariance or contravariance; array contravariance is, as you've discovered, not legal, and array covariance is making little time bombs in your program that go off unexpectedly. Make your arrays of the right type to begin with.
string[] newarr = Array.ConvertAll(objects, s => (string)s);
--EDIT--
since you've said I have an object (knowing that it is an object[] actually)
string[] newarr = Array.ConvertAll((object[])objects, s => (string)s);
object[] original = new object[]{"1", "2"};
//some code in between here
object obj = original ;
object[] objArray = (object[])obj;
string[] newArray = new string[objArray.Length];
for(int i = 0; i < newArray; i++)
{
newArray[i] = (string)objArray[i];
}
Other answers here are showing you quicker/shorter ways of doing the conversion. I wrote the whole thing out like this because it shows what's really going on and what needs to happen. You should use one of the simpler methods in your actual production code.
The rule in object oriented programming is -
"Derived class can always be type casted to base class" AND
"A Base class can be casted to derived class only if the current instance that base class hold off is actually derived class"
e.g. (A is base and B is derived)
A a = new B(); // legal;
B b = (B) a ; // legal as "a" is actually B (in first statement)
illegal : >
A a = new A();
B b = (B) a; // not legal as "a" is A only.
Same thing is applied to Object and String classes. Object is base class and string is Derived class.
You can convert the real string[] to object[].
This is a Array covariance
Can find a clear example in link.
You should cast each element in the collection and not the collection itself.
object[] ovalues = new object[] { "alpha", "beta" };
string[] svalues = ovalues.Cast<string>().ToArray();

Casting system.array to object in c#

my function has the following signature
function myfunction(ref object)
I use it as such
Array arr = Array.CreateInstance(System.Type.GetType("System.String"), 2);
arr.SetValue("1", 0);
myfunction( ref arr);
And I am getting
"cannot convert from 'ref System.Array' to 'ref object'"
I was under the impression that System.Array is object ...so why am I getting this error? Is object different from Object?
The problem you're having is that while an array is an object, an object is not an array, so in your function, if your array could be passed in as a ref object, the array could be assigned anything that is an object.
Edit:
To fix this problem declare a ref variable to use in place of the array variable:
Array arr = Array.CreateInstance(System.Type.GetType("System.String"), 2);
arr.SetValue("1", 0);
object referenceObject = arr;
myfunction( ref referenceObject );
Think of 'ref object' as "I take a reference to a variable that can store an Object". Suppose that 'myfunction' tried to store an 'int' to the variable you passed? This would fail at runtime, which is undesirable.
On a side note, you can use typeof(string) in place of calling GetType("System.String"). You can also just say:
Object arr = new string[2];
To access the array first, you can do this:
string[] arr = new string[2];
arr[0] = "1";
object arrObj = arr;
myfunction(ref arrObj);
I would double check that you're using the method myfunction correctly; it's a rather unusual parameter type for taking an initialized array.
Declare the variable as object and not as array.
To populate the array with values you should keep your array variable and declare another one to give it to the method.
Array myArray = ....;
Object myObject = myArray;
myFunction(ref myObject);
// Update the original reference
myArray = myObject as Array;

Assigning unassigned string to array

I've got a function which takes a ArrayList and loads it with strings along the line of
void func( ref ArrayList data )
{
if( data[0].GetType() == typeof(String) )
data[0] = "Jimmy";
}
In the function that calls func() I am having to create strings to put in the array:
ArrayList data = new ArrayList(1);
string str = "";
data.Add(str);
Is it possible to give the ArrayList the object types without having to create an object of that type? This:
ArrayList data = new ArrayList(1);
string str;
data.Add(str);
Gives a "Use of unassigned local variable 'str'" error.
#James and Guffa: Thanks for the 'stylistic' hints, I'm new to c# and the advice is much appreciated
No, that is not possible. What you want is a reference that points to a string, and that is only possible if it actually points to a string. The fact that the variable that holds the reference is declared as a string reference doesn't matter once you have copied the reference from the variable to the list.
I think that you should rethink the entire concept. I don't know your reason for sending in a list of values and replace them like that, but there has to be a more object oriented way of doing it.
The ArrayList class is practically obsolete, you should use a generic List<T> instead (even if you can't find any other common base class than object).
As you are always sending in a list object to the method and not replacing it with a new list object, you should not use the ref keyword. That's only for when you want to change the reference to the list, not the contents of the list.
You can send two parameters, one ref ArrayList in which members will be assigned and the other an ArrayList and the called function can assign at indexes in data where the type is String
If you are only wanting to keep this type safe then could you not use a List<T> class here instead e.g. List<string>?
What you're trying to do in your method with the above code is to call GetType() on null, which is not possible.
Why not use a generic list List<string> in this case? You can elegantly skip the part of using GetType() to determine the type with this approach:
static void func(List<string> data)
{
if(data.Count > 0)
data[0] = "Jimmy";
}
static void Main(string[] args)
{
List<string> lst = new List<string>(1);
string str = "";
lst.Add(str);
func(lst);
System.Console.WriteLine(lst[0]); //Prints out 'Jimmy'
}

Categories

Resources