C# function that accepts a jagged array of any dimension - c#

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.

Related

C# Array with specific LowerBound [duplicate]

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!

Why Can't I Specify The Size Of The Array Returned From A C# Function?

I know that the following C# code will not compile:
int[10] TestFixedArrayReturn(int n)
{
return new int[10]{n, n, n, n, n, n, n, n, n, n};
}
void TestCall()
{
int[10] result = TestFixedArrayReturn(1);
}
In order to get it to compile, I need to remove the array size from the function declaration (as well as the declaration of the result variable) like so:
int[] TestFixedArrayReturn(int n)
{
return new int[10]{n, n, n, n, n, n, n, n, n, n};
}
void TestCall()
{
int[] result = TestFixedArrayReturn(1);
}
I'm just wondering--why is that I cannot specify the size of the array of ints which will get returned? I take it what's getting passed back is actually a reference to the array (that'd be my guess anyway) but why can't I specify the size of the array being returned? Wouldn't this allow the compiler to check my code more closely for correctness?
The simple answer I think, is that in .net:
Functions return instances of a type
Therefore, functions are declared as having a return type
Arrays are a single type (Class) in .net, so that they can interoperate
Conversely, however, this means that arrays of different fixed sizes do not have different Types, just different instance attributes.
Which means that functions cannot be defined to return arrays of a specific fixed size because the length of an array is not part of its type specification, but rather part of its instance settings/attributes.
For variables, this seems like it can be done in the type declaration of variables, but it is actually part of the instance initialization specs there, even though syntactically it looks like it’s part of the type declaration. This was probably retained for style compatibility reasons with older languages like C, where things worked much differently under the hood.
For functions, however, the return object is not initialized where it is declared (in the function declaration) but rather procedurally in the body of the function itself. So allowing instance attributes to be set in the function declaration could have caused all kinds of conflicts and edge cases that would need to be checked either by the compiler or at run-time, neither of which was probably seen as being worth the very minimal gain.
An array is an array... it doesnt have a size unless you initialize it. When you are passing a variable from a method to another method, you define the type not its structure as in the size of the array.
How would the compiler know at compile time what the size of the array being returned would be? To work this out it would have to execute all the code in your method...

C# memory handling for methods

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;

What type is System.Byte[*]

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.

What is the generic alternative of Array?

In C# some collections such as ArrayList and HashTable have generic alternatives which are List<T> and Dictionary<TKey, TValue>.
Does Array also have a generic alternative?
No - just use a strongly typed array, e.g. int[]. It's relatively rare to use a "weakly typed" Array in the first place - in fact, I don't believe you can really create one. Every Array is really a strongly-typed one, even if you don't refer to it that way.
If you're looking for the generic collection type that most closely resembles an array, then you probably want a List<T>. But it's not really the same thing.
To expand on what others have said: the point of having generic types is so that a programmer can then use type-specific instances of those generic types, based on the needs of the current program. Arrays are already type-specific. You can always just take a T[].
For example, look at this simple function definition:
void SomeFunction(int[] x)
You could also think of it like this:
void SomeFunction<T>(T[] x)
where the programmer just chose to call it with an int for the type parameter:
SomeFunction<int>(myIntArray)
Array has always been, with special compiler support, somewhat generic.
E.g. System.Array allows objects in, but an int[] does not.
Expanding on Jon's answer
Arrays have no generic alternative because it's perfectly fine to have a generic array.
public static T[] CreateArray<T>(T item1, T item2) {
T[] array = new T[2];
array[0] = item1;
array[1] = item2;
return array;
}
There is no need for a generic alternative as when you define an array you state the type of the array. All the classes you mentioned are simple collection classes. An aray is a totally different data structure.

Categories

Resources