I'm being passed an object that returns "System.Byte[*]" when converted to string. This apparently isn't a standard one dimensional array of Byte objects ("System.Byte[]"), so what is it?
That's probably a single-dimensional array with a non-zero base.
Here's an example of how to create one:
using System;
class Test
{
static void Main()
{
Array nonZeroBase = Array.CreateInstance
(typeof(byte), new int[]{1}, new int[]{2});
Console.WriteLine(nonZeroBase); // Prints byte[*]
}
}
In CLR terminology this is called an array (rectangular arrays are also arrays) where single-dimensional, zero-based arrays are called vectors. (A multi-dimensional array would be printed as byte[,] though.)
You may be interested in this blog post which Marc Gravell posted just morning...
There is no ...[*] type in c# as far as I remember. Maybe you can find the API documentation for that library, that will show you what the type is really. Even if you don't have that, Visual Studio should show you the type when you try autocompletion on the method returning the object.
Related
Although perhaps a bizare thing to want to do, I need to create an Array in .Net with a lower bound > 0. This at first seems to be possible, using:
Array.CreateInstance(typeof(Object), new int[] {2}, new int[] {9});
Produces the desired results (an array of objects with a lower bound set to 9). However the created array instance can no longer be passed to other methods expecting Object[] giving me an error saying that:
System.Object[*] can not be cast into a System.Object[]. What is this difference in array types and how can I overcome this?
Edit: test code =
Object x = Array.CreateInstance(typeof(Object), new int[] {2}, new int[] {9});
Object[] y = (Object[])x;
Which fails with: "Unable to cast object of type 'System.Object[*]' to type 'System.Object[]'."
I would also like to note that this approach DOES work when using multiple dimensions:
Object x = Array.CreateInstance(typeof(Object), new int[] {2,2}, new int[] {9,9});
Object[,] y = (Object[,])x;
Which works fine.
The reason why you can't cast from one to the other is that this is evil.
Lets say you create an array of object[5..9] and you pass it to a function F as an object[].
How would the function knows that this is a 5..9 ? F is expecting a general array but it's getting a constrained one. You could say it's possible for it to know, but this is still unexpected and people don't want to make all sort of boundary checks everytime they want to use a simple array.
An array is the simplest structure in programming, making it too complicated makes it unsusable. You probably need another structure.
What you chould do is a class that is a constrained collection that mimics the behaviour you want. That way, all users of that class will know what to expect.
class ConstrainedArray<T> : IEnumerable<T> where T : new()
{
public ConstrainedArray(int min, int max)
{
array = new T[max - min];
}
public T this [int index]
{
get { return array[index - Min]; }
set { array[index - Min] = value; }
}
public int Min {get; private set;}
public int Max {get; private set;}
T[] array;
public IEnumerator<T> GetEnumerator()
{
return array.GetEnumarator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return array.GetEnumarator();
}
}
I'm not sure about why that can't be passed as Object[], but wouldn't be easy if you just create a real class to wrap an array and handle your "weird logic" in there?
You'd get the benefits of using a real reference object were you could add "intelligence" to your class.
Edit: How are you casting your Array, could you post some more code? Thanks.
Just store your lower bound in a const offset integer, and subtract that value from whatever your source returns as the index.
Also: this is an old VB6 feature. I think there might be an attribute to help support it.
The .NET CLR differentiates between two internal array object formats: SZ arrays and MZ arrays. MZ arrays can be multi-dimensional and store their lower bounds in the object.
The reason for this difference is two-fold:
Efficient code generation for single-dimensional arrays requires that there is no lower bound. Having a lower bound is incredibly uncommon. We would not want to sacrifice significant performance in the common case for this rarely used feature.
Most code expects arrays with zero lower bound. We certainly don't want to pollute all of our code with checking the lower bound or adjusting loop bounds.
These concerns are solved by making a separate CLR type for SZ arrays. This is the type that almost all practically occurring arrays are using.
Know it's old question, but to fully explain it.
If type (in this case a single-dimension array with lower bound > 0) can't be created by typed code, simply reflected type instance can't be consumed by typed code then.
What you have noticed is already in documentation:
https://learn.microsoft.com/en-us/dotnet/framework/reflection-and-codedom/specifying-fully-qualified-type-names
Note that from a runtime point of view, MyArray[] != MyArray[*], but
for multidimensional arrays, the two notations are equivalent. That
is, Type.GetType("MyArray [,]") == Type.GetType("MyArray[*,*]")
evaluates to true.
In c#/vb/... you can keep that reflected array in object, pass around as object, and use only reflection to access it's items.
-
Now you ask "why is there LowerBound at all?", well COM object aren't .NET, it could be written in old VB6 that actually had array object that has LowerBound set to 1 (or anything VB6 had such freedom or curse, depends whom you ask). To access first element of such object you would actually need to use 'comObject(1)' instead of 'comObject(0)'. So the reason to check lower bound is when you are performing enumeration of such object to know where to start enumeration, since element functions in COM object expects first element to be of LowerBound value, and not Zero (0), it was reasonable to support same logic on such instances. Imagine your get element value of first element at 0, and use some Com object to pass such element instance with index value of 1 or even with index value of 2001 to a method, code would be very confusing.
To put it simply: it's mostly for legacy support only!
Is there anyway to declare a function that takes in a jagged array of any dimension in C#? Right now if I pass in a jagged array in a function that takes in 1 dimensional arrays it would give me an error:
void func<T>(T[] arr){
return;
}
double[][] x = new double[10][];
func<double>(x);
// Error: cannot convert from double[][] to double[]
Is there any way I can change the function signature to make it accept both 1 dimensional array and jagged arrays? The function will only perform actions that would work on both jagged arrays and 1D arrays. I don't really want to use overload since the dimension of the jagged array might be unknown.
To accept an array argument of any type, any size, and any number of dimensions, you can use the Array class from the System namespace.
Here is what it would look like:
void Function(Array arr)
{
//Do your stuff with "arr",
//you can mostly just treat it like a normal array, looping and so on...
}
And if you would like to know the length of a specific dimension, just use the Array.GetLength(int Dimension) function.
If you would also like to know how many dimensions this array has, just use the Array.Rank property.
As for the question, you can simply do this and it wont cause any problems:
double[][] x = new double[10][];
Func<double>(x);
MS Doc:
https://learn.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1
https://learn.microsoft.com/en-us/dotnet/api/system.array.rank?view=netcore-3.1
Hope this helped you!
Is there anyway to declare a function that takes in a jagged array of any dimension in C#?
Yes, and you already actually have one. Your solution takes any T[], and T itself can be an array type - which is precisely how jagged arrays work. So let's take your original function (and just change the name to be more conventional and avoid confusion with the Func delegate type):
void ProcessArray<T>(T[] array)
{
// (Method body is irrelevant for now)
}
If you want that method to process a double[], then the type argument for the method (i.e. the type of T for that method invocation) needs to be double. If you want the method to process a double[][], the type argument needs to be double[], and so on.
You can do this by explicitly specifying the type argument:
double[] simpleArray = new double[10];
ProcessArray<double>(simpleArray);
double[][] jaggedArray = new double[10][];
ProcessArray<double[]>(jaggedArray);
Alternatively, you can use generic type inference to let the compiler figure out what type argument you want for T automatically:
double[] simpleArray = new double[10];
ProcessArray(simpleArray);
double[][] jaggedArray = new double[10][];
ProcessArray(jaggedArray);
In my experience, you can usually use type inference when calling generic methods, but there are exceptions where you need to specify the type arguments explicitly.
The problem you faced was that you were providing a type argument of double, but a regular argument of type double[][].
Now, if in your method you want to process all the individual elements, e.g. recursively calling your method with each of the "less jagged" arrays, you may need to use either reflection (e.g. typeof(T).GetElementType()) or members of the Array type to get more information at execution time. We don't know what your method needs to accomplish, so we can't provide any more concrete advice than that right now - but hopefully you can experiment with those two approaches.
<T> means any type. As long as you respect the operations and the valid states of this mystical type <T> it can be anything. Furthermore, is deduced from the types you feed the method as its parameters, so you need only to be explicit when declaring it but not when invoking it.
So, you made a change to accept N-dimensional arrays called... idk, Transform:
This could be its signature: void Transform<T>(T array). In this case T is already an array, if the parameter was an array of type T (example: void f<T>(T[] a) this would be the signature, and so on.
T is a template, a type potentially built when you compile (and sometimes even at runtime). The power of template programming immense, and due to C#'s coder first philosophy we get to experience in its full glory without having to shed several tears over a C++ text-book.
I have a quick question (this is in C#). Let's say I have an array of numbers:
int[] count = new int[4] {0, 4, 3, 2};
I have a method that does some stuff:
public void Invert(int[] arrayVar)
{
for (int i = 0; i < arrayVar.Count; i++)
{
//arrayVar[i] = stuff
}
}
If I call the method by doing this:
Invert(count);
Is there a way to have the method directly edit the count array instead of just duplicating it and editing the duplicate? I can't have a global variable for multithreading reasons and I can't return the end result because I have similar methods that have to return very specific things. Is this possible? Thanks!
Is there a way to have the method directly edit the count array instead of just duplicating it and editing the duplicate?
Yes. Do exactly what you are doing. Your program already does exactly what you are asking for.
Arrays are passed by reference in C#. count and arrayVar refer to the same array. When you pass an array to a method, that method does not get a copy of the array. It gets a copy of a reference to the array.
Changes that you make to arrayVar inside Invert will also be made to count inside the caller because those two variables both contain a reference to the same array.
Do not confuse this with the ref feature of C#. Ref makes two variables act as though they are the same variable. Here you have two different variables that both refer to the same array. Make sure that the distinction is clear in your mind.
A number of answers confusingly suggest that you use a list instead of an array. Lists are also reference types; they have the same semantics as arrays when passed to a method. That is, the passed-in value is a reference. The reason to use a list instead of an array is because lists are more flexible and powerful than arrays. Arrays are fixed in size; an array with ten elements always has ten elements. A list can have new elements added or old elements removed.
I have a question about they way C# functions, or methods, handle memory when certain objects are used as input arguments. I have tried searching for an answer to this but haven't been able to find anything, I might not know what to look for though.
The question: Say I have a really big integer array of size 10.000 by 10.000, called 'MyArray'. Lets say I moreover have some method called 'MyMethod' which takes several entries from two specified rows (this is the input) from MyArray and performs some operations on it, such as adding or multiplying these numbers, and then returns another integer.
To keep my code as short as possible I would prefer to make a method
MyMethod(int i, int j, int[][] MyArray)
rather than having to enter all the numbers from the array as seperate arguments. However does this mean the method creates a copy of MyArray when it is called or does C# know that if this data is only read and not edited in any way, that making a copy isn't needed?
In C#, arrays are actually objects, and not just addressable regions of contiguous memory as in C and C++. Thus, in our case, only the reference of the array is passed as an argument for the method.
C# does not create a copy as the array will be passed as a reference (like a C++ pointer) to the method. In general only struct types will be passed as a copy and normal class instances will be passed as a reference.
You can read more on the topic on MSDN
As you can read here : MSDN - Passing arrays as argument
Arrays can be passed as arguments to method parameters. Because arrays are reference types, the method can change the value of the elements.
Arrays are classes, and that's why they're just references and when we pass array into a method all we need is to pass an address (4 or 8 bytes). Proof:
Boolean isClass = typeof(int[][]).IsClass; // <- return true
Structs are passed by value, e.g. int is a struct:
Boolean isClass = typeof(int).IsClass; // <- return false;
here is the situation: I want to call a method from a C++ module, and pass an array to it:
x.Method(array, ...)
x is a C# object. I would suppose that I could change the array and fill it with my own data - but it seems not be the case (?)
How should I pass the array by reference and change its content in the method?
Thank you in advance,
cheers.
Yes, if you want to alter the array beyond just altering its elements (i.e. adding or removing elements) then you have to pass it by reference. The C# declaration would be:
public void Method(ref Mumble[] arg)
Which isn't great syntax. The garbage collector makes it easy to return an array as the function return value:
public Mumble[] Method(Mumble[] input)
But consider a List<Mumble> instead.
You don't need to pass the array by reference. Array is a reference type, so if you pass the array to the method, you're actually passing a reference to it. The method can change the content of the array pointed by the reference, but cannot change the reference itself (i.e. it can't make it point to a different array). If you were passing the array by reference, the method would be able to change the reference to the array, but that's probably not what you're looking for if you just want to fill an existing array.
I suggest you have a look at this article for more details