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.
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!
By accident, it appears I am creating an unbounded array, which I didn't think was possible in c#. I am not getting any errors, and the code works, but I see no reference to the array declaration I used in online documentation. I tried using this method in other situations and I get an error every time. Why does this work?
Array arrLines;
arrLines = System.IO.File.ReadAllLines(strTargetFilePath2);
foreach (string strLine2 in arrLines)
{
eventLog1.WriteEntry(strLine2);
}
Array arrLines; does not actually create an array. It just sets up a variable that you can assign an array to.
You don't have to set up a length when you declare arrLines because it is a reference type, which means that it holds an address to the hypothetical array content instead of the array content itself.
System.IO.File.ReadAllLines(strTargetFilePath2);
is what creates the array, and yes, that array does have a specific length.
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;
Is it possible to fully remove Array in C# but not to fill it with 0's:
for(int i=0;i<a.Length;i++)
{
a[i]=0;
}
or Array.Clear(a,0,a.Length);
But to clear it in a way that List.Clear() does so that it's size will be 0 again like before filling.
I tried
a=new int[15]; but prevous values where still there. Thanks!
Arrays in C# are fixed-length; you cannot change the size of an array. You can allocate an array of a different size and copy the elements in order to simulate resizing (this is exactly what List<T> does internally), but you cannot "clear an array" in the sense that you reduce it to zero elements.
I tried a=new int[15]; but prevous values where still there.
The previous values cannot possibly still be there, because this allocates a new int array of 15 elements, where all elements are zero.
Note that this does not alter the array that a referenced; rather, it creates a new array and stores a reference to it in a. So if you initialized a from another array variable, they would have referred to the same array, but after assigning a new array to a the other variable would continue to point to the old array. Perhaps this is where the "previous values" are coming from.
var a = new int[] { 1, 2, 3 };
var b = a;
// a and b now reference the same array.
a = new int[] { 4, 5, 6 };
// a is now {4,5,6} but b remains {1,2,3}
As others have said, it depends on the type semantics that you're putting into the array.
Value types (such as int, bool, and float) are ... well, values. They represent a quantity, something tangible, a state. Thus, they are required to be known at compile time and have a default value.
By contrast, reference types (basically every class) don't actually hold any values themselves, but "group" data together by means of reference. Reference types will either point to other reference types, or eventually to a value type (which holds actual data).
This distinction is important to your question. List<T> is a dynamically sized collection that can grow or shrink without creating a new object because of how it is implemented. Each element in the list points to the next element, thus it's size cannot be known ahead of time.
Arrays are a fixed-size collection that are declared to be a specific size. The type of array determines how much memory is reserved by the system. For example a byte[] of 100 elements will consume less memory than an Int64[] array of 100 elements. Thus, the system needs to know ahead of time how many bytes to reserve in total, which means it needs a default value to "fall back" on to satisfy compile-time checking. Where T[] is a reference type/class, this is null. For value types, this is usually 0 (or default(T)).
If you wanted to remove all the values of an array, similar to how List.Clear() works, you can do int[] a = new int[0];, but note that you are creating an entirely new array and reallocating the memory for them (hence the keyword new). Other objects will need to reference this new array. By design, you can't simply resize an array. A list is a mutable collection and supports changing the number of elements. You could also try int[] a = null, but this sets it to no object at all, which is again, something different.
It depends whether the array's elements are Value type or Reference type.
In your case it is value type so you'll have to have some value in it. You can not assign null to it.
Because value type objects have some default values.
int[] x = new int[5];
x[0] = 1;
x[1] = 2;
x[2] = 3;
x[3] = 4;
x[4] = 5;
System.Collections.ArrayList y = new System.Collections.ArrayList(5);
y.Add(1);
y[2] = 2;
The above gives a run time exception "Index was out of range. Must be non-negative and less than the size of the collection."
Why is this so ? Can't we add data into ArrayList using index same as int[] Array? Please provide me with some pointers to understand the reason behind this implementation.
Your ArrayList only has one entry in it, and so index 2 is out of range. ArrayList#Add adds to the list. Your list has an initial capacity of 5 because you called the ArrayList(Int32) constructor, but you've only added one actual entry to it (which will be at index 0).
The only thing you seem to have misunderstood is what the ArrayList constructor does. new ArrayList(5) does not create an ArrayList with five elements, as opposed to new int[5], which does create an array with five elements (all having the value zero). A newly-created ArrayList is always empty, so any attempt to use [] to set the value of any element will crash, because there are no elements. This is the same behavior as a regular array if you had created an array by saying new int[0] - any attempt to index into it would crash. The only way to get a five-element ArrayList is to either use the constructor that takes a (five-element) collection as a parameter (as #Stilgar and #Kelon showed), or by calling e.g. Add(0) five times. After having done this, you can access x[0], x[1], ..., x[4].
What does new ArrayList(n) do, then? It creates an ArrayList of size zero, but where the internal array that is used to store the values is given the size n, so that we can add n elements before the internal array must be replaced by a bigger one (which takes a little bit of time, which is why you in high-performance scenarios might want to use this constructor if you know how big the list will eventually become).
new ArrayList(5) just allocates memory for 5 entries. That's all. You still have to add or insert to a list - it's not the same as an array.
Maybe you need to use a collection rather than an array like a List<int>();
As for why see this
http://msdn.microsoft.com/en-us/library/k2604h5s(v=vs.80).aspx
Class library designers might need to
make difficult decisions about when to
use an array and when to return a
collection. Although these types have
similar usage models, they have
different performance characteristics.
In general, you should use a
collection when Add, Remove, or other
methods for manipulating the
collection are supported.
For more information about using
collections, see Collections and Data
Structures.
Arrays initializes the memory with default values. Lists have different semantics. They are supposed to manage their size dynamically. The capacity you've provided (5) is purely optimization based on the specific list implementation. Not every IList implementation would have the same internal representation. What if the implementation was a LinkedList? You need to think about the concept of the data structure List not about the particular implementation.
If you want to assign values there are plenty of ways to initialize a list. You can pass an array to the constructor or use the collection initializers from C# 3.0. And please use List instead of ArrayList.
//Collection initializer
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
//passing array as an argument to the constructor
int[] ints = new[] { 1, 2, 3, 4, 5 };
List<int> list2 = new List<int>(ints);
Try
new ArrayList(new int[5]);
this initializes the ArrayList with 5 given default entries.
But
y.Add(1); // would add a 6t entry
You can specify the capacity when creating the ArrayList, but this is only so that the object can allocate space internally, the initial size of the list is still zero.
The difference between an ArrayList and an array is that the size of the list is dynamic. You can add and remove items, which is not possible with an array. It makes sense for a dynamically sized collection to start with the size zero, instead of filling it with zero-values.
Note: The ArrayList class is practically obsolete; you should use the generic List<T> class instead, which performs better and is easier to use, especially for value types like int.