Array through parameter by reference affecting another array - c#

CardDetails is a Structure.
public static void ParceIntricaciesJabber(ref CardDetails[] WhichArray)
{
WhichArray[0].ID = 50;
WhichArray[0].Type = "None";
}
In calling:
ParceIntricaciesJabber(ref OpponentCards);
After I call the function though, another Array called PlayerCards is affected in the exact same way as OpponentCards - despite being declared as two different arrays. They have the same number of elements and the same data Type, and that's it.
This probably should be obvious but i'm not seeing it. The code works in VB.NET. What am I doing wrong?
EDIT: Initialization Code:
public static class Module1{
public static CardDetails[] PlayerCards = new CardDetails[100];
public static CardDetails[] OpponentCards = new CardDetails[100];
}
And also when navigating to the Form
for (int n = 1; n <= 100; n++)
{
Module1.PlayerCards[n] = new CardDetails();
Module1.OpponentCards[n] = new CardDetails();
}

My guess is that you are sharing the reference to the arrays. Even though it is structs inside the array, the array itself is a reference type. You will need to post your array instantiation code to verify one way or the other though

Related

Instantiation of every array element(class) - C# [duplicate]

Given a class:
class clsPerson { public int x, y; }
Is there some way to create an array of these classes with each element initialized to a (default) constructed instance, without doing it manually in a for loop like:
clsPerson[] objArr = new clsPerson[1000];
for (int i = 0; i < 1000; ++i)
objArr[i] = new clsPerson();
Can I shorten the declaration and instantiation of an array of N objects?
The constructor must be run for every item in the array in this scenario. Whether or not you use a loop, collection initializers or a helper method every element in the array must be visited.
If you're just looking for a handy syntax though you could use the following
public static T[] CreateArray<T>(int count) where T : new() {
var array = new T[count];
for (var i = 0; i < count; i++) {
array[i] = new T();
}
return array;
}
clsPerson[] objArary = CreateArray<clsPerson>(1000);
You must invoke the constructor for each item. There is no way to allocate an array and invoke your class constructors on the items without constructing each item.
You could shorten it (a tiny bit) from a loop using:
clsPerson[] objArr = Enumerable.Range(0, 1000).Select(i => new clsPerson()).ToArray();
Personally, I'd still allocate the array and loop through it (and/or move it into a helper routine), though, as it's very clear and still fairly simple:
clsPerson[] objArr = new clsPerson[1000];
for (int i=0;i<1000;++i)
clsPerson[i] = new clsPerson();
If it would make sense to do so, you could change class clsPerson to struct Person. structs always have a default value.

c# Confusion over what type of array and usage

I am new to c# and am trying to build an array of arrays of items. I have looked at 2d arrays and jagged arrays and simply can't work out what i'm supposed to be using and can not get it to work. It's not so much building the array it's then looping through it to interrogate the array elements. I'm working within an existing library which is where all the variables come from, most of the other supporting code I've left out as it's not relevant. Once a instance is found i'm then trying to update a field from 0 to 1. Many thanks for any help in advance.
//Declare array
private double[,] myOpenTrades;
private void mymethod (double score, double RSIComboScore, int type, int line)
{
myOpenTrades[line,0] = type;
myOpenTrades[line,1] = CurrentBar;
myOpenTrades[line,2] = Close[0];
myOpenTrades[line,3] = rewardClose;
myOpenTrades[line,4] = riskClose;
myOpenTrades[line,5] = score;
myOpenTrades[line,6] = RSIComboScore;
myOpenTrades[line,7] = this.getSMATrend();
myOpenTrades[line,8] = Math.Round(NSRSICS(5, 15, 60, 240).Rsi200AVGPlot[0]);
myOpenTrades[line,9] = myReward;
myOpenTrades[line,10] = myRisk;
myOpenTrades[line,11] = 0;
}
protected override void OnMyChange()
{
foreach(double[] row in myOpenTrades)
{
if(Close[0] >= row[3] && row[11]==0)
{
Print("WIN:"+row[10]);
row[11]=1;
}
else if(Close[0] >= row[4] && row[11]==0)
{
Print("LOSE:"+row[9]);
row[11]=1;
}
}
{
I don't know why this is being downvoted, it seems like a legitimate question from a new user who made some effort.
To answer your question, an array of arrays is not the best choice, because from a logical organization perspective you don't have a "grid" (i.e. 2D array) of the same item, you have multiple items as one record, and an array of records. Not to mention that you appear to be trying to mix and match types; your array is declared as double but the first record type is an integer.
I would recommend using a class as follows:
class OpenTrades
{
public int Type;
public Bar CurrentBar;
public double Score;
// etc...
}
(This is assume that CurrentBar's type is Bar; you'll have to substitute Bar with whatever that type actually is.)
Then you would instantiate an array of your class like this:
OpenTrades[] myOpenTrades = new OpenTrades[11]; // This will create an array of 11 elements, indices 0 to 10
Now in your mymethod function you can assign values to each of your members.
myOpenTrades[line].Type = type;
myOpenTrades[line].Bar = CurrentBar;
myOpenTrades[line].Score = score;
// etc ...

Is this a good practice of immutability?

Good morning,
Suppose I have a class
public class Class
{
int something;
int[] otherThing;
}
and I want to make objects of type Class immutable. Suppose also that I have a very frequent operation which creates a new object of type Class,
public Class SomeFunction()
{
int[] Temp = new int[] { ... };
return new Class(1, Temp);
}
To avoid creating new objects too often, and since Tempis no longer accessible out of the method, is it too bad to set on the constructor
this.otherThing = Temp;
instead of
otherThing = new uint[Temp.Length];
for (int i = 0; i < Temp.Length; i++)
{
this.otherThing[i] = Temp[i];
}
?
Thank you very much.
If the constructor that does this is private its fine IMO. Since you know the content of the other array will never change you can directly use it. You could even share one instance of the array between several instances of your class if you want to without causing any problems.
A public constructor directly using a provided array is a bad idea on the other hand. Since that can be used to break immutability.
It is better to assign a copy of temp to otherThing so that any changes to otherThing will not change temp. You can also use the Array.CopyTo method for this purpose.
In addition you should seriously consider using IEnumerable<int> or IList<int> instead of int[] because arrays by nature work against the idea of immutability. Read this blog post by Eric Lippert.
The difference is that in the first option you always get a new instance and in the second one all the created "Class"es will point to the same array (!). So if you change something in the array in any Class, all the other classes are changed.

Why Can I Change Struct's int[] Property from Method Without Specifying "ref"?

From a method, I can pass a struct which contains an array of integers, and change the values in the array. I am not sure I understand fully why I can do this. Can someone please explain why I can change the values stored in the int[]?
private void DoIt(){
SearchInfo a = new SearchInfo();
a.Index = 1;
a.Map = new int[] { 1 };
SearchInfo b = new SearchInfo();
b.Index = 1;
b.Map = new int[] { 1 };
ModifyA(a);
ModifyB(ref b);
Debug.Assert(a.Index == 1);
Debug.Assert(a.Map[0] == 1, "why did this change?");
Debug.Assert(b.Index == 99);
Debug.Assert(b.Map[0] == 99);
}
void ModifyA(SearchInfo a) {
a.Index = 99;
a.Map[0] = 99;
}
void ModifyB(ref SearchInfo b) {
b.Index = 99;
b.Map[0] = 99;
}
struct SearchInfo {
public int[] Map;
public int Index;
}
In C#, references are passed by value. An array is not copied when passed to method or when stored in an instance of another class. - a reference to the array is passed. This means a method which recieves a reference to an array (either directly or as part of another object) can modify the elements of that array.
Unlike languages like C++, you cannot declare "immutable" arrays in C# - you can however uses classes like List which have readonly wrappers available to prevent modification to the collection.
From a method, I can pass a struct which contains an array of integers, and change the values in the array. I am not sure I understand fully why I can do this.
An array is defined as a collection of variables.
Variables, by definition, can be changed. That is why we call them "variables".
Therefore when you pass an array, you can change the contents; the contents of an array are variables.
Why can I change a struct’s int[] property without specifying “ref”?
Remember, as we discussed before in a different question, you use ref to make an alias to a variable. That is what "ref" is for -- making aliases to variables. (It is unfortunate that the keyword is the confusing "ref" -- it probably would have been more clear to make it "alias".)
From MSDN:
Do not return an internal instance of an array. This allows calling code to change the array. The following example demonstrates how the array badChars can be changed by any code that accesses the Path property even though the property does not implement the set accessor.
using System;
using System.Collections;
public class ExampleClass
{
public sealed class Path
{
private Path(){}
private static char[] badChars = {'\"', '<', '>'};
public static char[] GetInvalidPathChars()
{
return badChars;
}
}
public static void Main()
{
// The following code displays the elements of the
// array as expected.
foreach(char c in Path.GetInvalidPathChars())
{
Console.Write(c);
}
Console.WriteLine();
// The following code sets all the values to A.
Path.GetInvalidPathChars()[0] = 'A';
Path.GetInvalidPathChars()[1] = 'A';
Path.GetInvalidPathChars()[2] = 'A';
// The following code displays the elements of the array to the
// console. Note that the values have changed.
foreach(char c in Path.GetInvalidPathChars())
{
Console.Write(c);
}
}
}
You cannot correct the problem in the preceding example by making the badChars array readonly (ReadOnly in Visual Basic). You can clone the badChars array and return the copy, but this has significant performance implications.
Although your SearchInfo struct is a value type, the .Map field is holding a reference, because Array is a reference type. Think of this reference as the address pointing to the memory location where the array resides.
When you pass an instance of SearchInfo to a method, as you know, the SearchInfo gets copied. And the copy naturally contains the very same address pointing to the very same array.
In other words, copying the struct doesn't make a copy of the array, it just makes a copy of the pointer.
Well, it is passed by reference anyway, like all reference types in C#.
Neither C# nor CLR support constness, unfortunately, so the platform doesn't really know if you are allowed to change it or not. So, it has the reference, it may use it to change the value, and there's nothing to stop it from doing so.
You may see it as a language design bug, btw. It is unexpected for the user.

C# constructor help

In the following code block, why do I need to declare myData in the class, then initialize myData = new string[size] in the constructor? Why is it illegal to code private string[] myData = new string[size] ?
That is, why do I need to do:
class IntIndexer
{
private string[] myData;
public IntIndexer(int size)
{
myData = new string[size];
for (int i = 0; i < size; i++)
{
myData[i] = "empty";
}
}
}
Instead of
class IntIndexer
{
private string[] myData = new string[size];
public IntIndexer(int size)
{
for (int i = 0; i < size; i++)
{
myData[i] = "empty";
}
}
}
Because the variable "size" only exists in the constructor.
Because you do not know what size will be, or even if it exists outside the constructor.
Inline initialisers run as part of all constructors in the class. Adding another constructor without size would break your class if this were implemented, a confusing state of affairs.
Also even if the compiler were made smart enough to check for all this it would be a confusing abuse of scope. What if there were a constant field called size somewhere else in the class?
All these are reasons to not attempt to allow this sort of thing and there are precious little benefits to it so why bother.
Because size is only known to the constructor at run-time - not compile-time. If you wanted to size myData to a constant size - i.e. known at compile-time, then you could do it in the declaration:
private string[] myData = new string[1000];
or
private const int DATA_SIZE = 1000;
private string[] myData = new string[DATA_SIZE];
Because size is a parameter of the constructor and only exists within the scope of the constructor.
The issue here is one of scope. You can't reference size, a parameter of the constructor, outside the constructor because it isn't defined outside the constructor. This will give you a compile error. If the variable were defined in the object, it would be perfectly legal, but you'd be dependent on the order of initialization as to whether you would get the effect you intended. If the initializer for the variable were run before the initializer for the array, then it might work. IMO, you're better off doing the initialization in the constructor because that way you define the order of execution and know what will happen, when.
Because you don't know the size until the constructor is called. The following field definition is fine:
private string[] myData = new string[100];
you cannot do that for one reason: How would the compiler know how big size is at compile time?
if you want to initialise an array with a runtime-variable size, you must initialise it within a runtime method when the variable has a value!
Because if you try to do in this way
class IntIndexer
{
private string[] myData = new string[size];
public IntIndexer(int size)
{
for (int i = 0; i < size; i++)
{
myData[i] = "empty";
}
}
}
you will get compilation error
The name 'size' does not exist in the current context.
beacuse at this point
private string[] myData = new string[size];
size is not yet declared.
And if you will write in this way from where you will get the value of size as your objective i think will be to make it flexible and let the instance do that for you that's why your objective can be done by this
class IntIndexer
{
private string[] myData;
public IntIndexer(int size)
{
myData = new string[size];
for (int i = 0; i < size; i++)
{
myData[i] = "empty";
}
}
}
ie you will be setting that size like this
IntIndexer instance = new IntIndexer(100);

Categories