C# array of variables - c#

Is it possible to do something like this:
string A = "A";
string B = "B";
object[] O = { A, B };
O[0] = "C";
Where A will hold the value "C" in the end?
The code above will replace O[0] with "C", but A remains unchanged.

No - at least not in safe code.
When you create the array, it copies the values into the array. Changing the value in the array later won't change the value of the variable. There's no way of creating a sort of "ref array", where the array elements are shared with the variables. (As shown in Mark's answer, there are sometimes ways of doing this in unsafe code, but I'd really suggest staying away from that.)
Note, however, that if both the array and the variable refer to the same mutable object then mutating that object via either path will make a change which is visible via the other:
StringBuilder x = new StringBuilder();
StringBuilder[] array = new StringBuilder[] { x };
array[0].Append("Foo");
Console.WriteLine(x); // Prints "Foo"
This is no different to any other assignment though - and note that in the code above, the Append call doesn't change the value of either x or the array element; it changes the data within the object that those values refer to.

While the answer is no in the case of string, you can do this with value types:
class Program
{
static unsafe void Main()
{
char A = 'A';
char B = 'B';
var O = new char*[] { &A, &B };
*O[0] = 'C';
System.Console.WriteLine(A + "," + B); // outputs C,B
}
}
Unsafe code is typically frowned upon in C#. So, while this kind of thing is possible, I wouldn't recommend doing it.

What you probably want is to convert your strings into objects with properties.
You can then Cast your array object on the specific key to this object type you created, and then you can set its property again.
This way you can change both what's in your array, as your original variable, therefor, it is similar to seeing it as an array with values by reference.
public class stringObject
{
private string name;
public string Name { get { return name; } set { name = value; } }
}
stringObject A = new stringObject();
A.Name = "A";
stringObject B = new stringObject();
B.Name = "B";
object[] O = { A, B };
//change the array at key 0, and also changing our original variable
stringObject C = O[0] as stringObject;
C.Name = "C";
The above code will not only change what is inside O[0], but it will also update what is inside your object A.
An example with a test to write to the console can be seen here:
https://dotnetfiddle.net/Yt25hy

Related

How to deal with arrays inside a struct?

I'm looking for a way to replace some of my List objects with arrays in my project to boost performance. The reasoning is that the List I would replace do not change size often (sometimes only once), so it would make sense to swap them out with arrays. Also, I would like to prevent allocations on the heap as much as possible.
So my idea is to create a struct (ArrayStruct) with two members "Count" and "Array". The struct would have some functions to add/remove/get/set/ect... elements in the array. The count would keep count of the elements that are usable in the array, and the array would only increase in size, never decrease.
Note that this is for a very particular case because I know the array size won't be very big.
The main problem I have is when I pass the reference to an already existing ArrayStruct object (named a in the example) to another (named b in the example) - I can edit the array in it, but once I resize it in a, I get an out of range exception in b. Is this because of the way I'm updating the reference via System.Array.Resize, so that the object b somehow does not attribute this change?
The only thing I could come up with as an idea was trying to override the assignment operator so that it would create a new array on assignment... but obviously that does not work.
My ArrayStruct
public struct ArrayStruct<T>
{
[SerializeField] private int m_Count;
[SerializeField] private T[] m_Array;
public int Count => m_Count;
public void Initialize(int startSize)
{
m_Count = 0;
m_Array = new T[startSize];
}
public T GetAt(int index)
{
return m_Array[index];
}
public void SetAt(int index, T newValue)
{
m_Array[index] = newValue;
}
public void Add(T newElement)
{
if (m_Array == null) {
m_Array = new T[1];
} else if (m_Array.Length == m_Count) {
System.Array.Resize(ref m_Array, m_Count + 1);
}
m_Array[m_Count] = newElement;
m_Count++;
}
public void Remove(T element)
{
for (int i = 0; i < m_Count; ++i) {
if (!element.Equals(m_Array[i])) {
continue;
}
for (int j = index; j < m_Count - 1; ++j) {
m_Array[j] = m_Array[j + 1];
}
m_Count--;
m_Array[m_Count] = default(T);
break;
}
}
//Trying to overload the = operating by creating a auto cast, this gives a compile error
/*public static implicit operator ArrayStruct<T>(ArrayStruct<T> otherArray)
{
var newArray = new ArrayStruct<T>();
newArray.m_Count = otherArray.Count;
newArray.m_Array = new T[otherArray.Length];
otherArray.m_Array.CopyTo(newArray.m_Array);
return newArray;
}*/
An example showcasing the problem
var a = new ArrayStruct<string>()
a.Add("hello");
var b = a;
print (b.GetAt(0)); //"hello"
a.SetAt(0, "new value for a");
print(b.GetAt(0));//"new value for a" , changing a changed b because the array is the same in both, this is bad
a.Add("resizing array");
print (b.GetAt(1)); //"Out of range exception" , because the array was resized for a but not for b therefore the connection broke
So do any of you have an idea of how I could make a new copy the array when I assign the struct to another variable?
Of course, I know I could use a function to do something like so
b = new ArrayStruct(a);
But I want it to be implicit. Or if there was a way to prevent assignments that would also work for me.
var a = new ArrayStruct();//let this work
var b = a; //Prevent this from happening
If you have any other solutions for replacing Lists with arrays conveniently please let me know
So do any of you have an idea of how I could make a new copy the array when I assign the struct to another variable? Of course, I know I could use a function to do something like so b = new ArrayStruct(a); But I want it to be implicit.
You can't do that. If a is a struct and you execute var b = a, then it will always just set b to a shallow copy of a; there's no way to change that behavior.
Doing something like b = new ArrayStruct(a) is the best you can do.
You're not understanding what the "=" operator is doing there. Objects are defined by reference, meaning when you write var b = a; you are actually asking for what you wish to avoid to happen, that is - object "b", pointing to the same object, which is "a".
You're passing the object "b" to point to the reference of object "a", which object holds the address to the object in question you defined, using the new keyword var a = new ArrayStruct<string>()
Your operator overloading does not work because you can't use it for conversions of the same type as the class you're writing the operator in. You'd either have to make a separate object (class), which would defeat the point you're trying to fix, or pass the m_array instead: public static implicit operator ArrayStruct<T>(T[] array)
You can also do something like this:
public static ArrayStruct<T> CopyFrom (ArrayStruct<T> array)
{
var newArray = new ArrayStruct<T>();
newArray.m_Array = new T[array.Count + 1];
newArray.Count = array.Count;
Array.Copy(array.m_Array, 0, newArray.m_Array, 0, array.m_Array.Length);
return newArray;
}
Now it should work exactly as you wanted.
var a = new ArrayStruct<string>();
a.Add("hello");
var b = ArrayStruct<string>.CopyFrom(a);
a.SetAt(0, "new value for a");
a.Add("resizing array");
Console.WriteLine(b.Count); // b returns 1
Console.WriteLine(a.Count); // a returns 2
As to why your index was going out of bounds, i.e it did not preserve the reference found in "a", this is all in correlation with references, yet again.
In the following code System.Array.Resize(ref m_Array, Count + 1); you're changing the reference found for object m_array in "a", when you're adding the new element with the line a.Add("resizing array");. That essentially means that your "a" object's m_array (which is another object of type array[]) is now pointing to a new object (of type array[]), which is of a new size.
Okay, but object "a" is now using the new reference, whilst object "b" is still using the old one. m_array in object "b" only has a single element, while the new m_array object in "a" has the newly added element "resizing array", along with any previously added ones.
I believe that's how System.Array.Resize works? Edit me if I'm wrong.
Below is a resource explaining how to do a deep cloning of an object, if that's what you truly wish to do (i.e create a completely new copy of an object, as well as any other objects inside)
Deep cloning of objects

How to create mutable .NET strings?

.NET strings are always immutable, but how can one make an equivalent System.String class that the string values can be mutated?
For example: When a is changed, I want b also be changed.
var a = "Hello";
var b = a;
a = "World";
var shouldBeTrue = String.ReferenceEquals(a, b)
&& String.Equals(b, "World");
Strings are inmutable, wich was a very important design Decisions. It helps using them in Multitasking contexts and allows a bunch of other Optimizations like String Interning.
Usualy the inmutabiltiy is not a problem. Unless you are doing loads of string operations, what little dead strings accumulate can be dealt with by the GC whenver it coems around to running.
For the remaining cases, there is the StringBuilder class. Whose purpsoe is to get around inmutability and stuff like internening. On a more extreme level you might make your own Char list or array. Just do not forget to provide a custom ToString(). But for at least 95% of all cases the String and StringBuilder classes are enough.
Edit:
After reading a Comment to your Originbal post, I too noticed that mutabiltiy does not seem to be what you are actually looking for. Rather then you seem to look for is normal reference mechanics. While this thematic is somewhat related to inmutability, it is actually a distinct property. ref should work. As would be just making a class with a single string field and handing the instances of that class around.
As #Christopher noted, most likely what you really want is not string mutability, but rather a reference mechanic by which multiple such references are kept synchronized. The simplest such mechanism would be a wrapper class, like in the example below:
class Wrapper
{
public string Value { get; set; }
}
static void Main(string[] args)
{
Wrapper a = new Wrapper();
a.Value = "Hello";
Wrapper b = a;
a.Value = "World";
System.Diagnostics.Debug.Assert(ReferenceEquals(a, b));
System.Diagnostics.Debug.Assert(a.Value == b.Value);
}
var a = "Hello";
var b = a;
var chars = new char[] { 'W','o','r','l','d' };
unsafe
{
fixed (char* pTempChars = &a.GetPinnableReference())
{
char* ptr = pTempChars;
for (int i = 0; i < chars.Length; i++)
{
(*ptr) = chars[i];
ptr++;
}
}
}
var shouldBeTrue = String.ReferenceEquals(a, b) && String.Equals(b, "World");
//shouldBeTrue is true
But it can be dangerous. You must be sure that no one other than b and a refers to them. And it only works if the length of the string is the same.
Update(More readable but less flexible):
var a = "Hello";
var b = a;
ChangeString(ref a, "World");
var shouldBeTrue = String.ReferenceEquals(a, b) && String.Equals(b, "World");
//shouldBeTrue is true
___________________
var a = "Hello";
var b = a;
ChangeString(ref a, "Wor");
//b == "Worlo"
private bool ChangeString(ref string original, in string newValue)
{
if(original.Length < newValue.Length)
{
return false;
}
unsafe
{
fixed (char* pDest = original, pSource = newValue)
{
Buffer.MemoryCopy(
pSource,
pDest,
original.Length * sizeof(char),
newValue.Length * sizeof(char)
);
}
}
return true;
}
System.Text.StringBuilder Class is a mutable string. You can use the indexer to change the char in pos (one char only), and use the Insert, Replace, Append, and AppendLine to make changes to the StringBuilder itself in the fastest way possible. These methods return an instance to the same string builder object, so, you don't actually need to assign the return value.

Use a variable value as a part of array name

I've read other similar Questions. But, All of them use bash. IDK anything about that language.
The Thing I want to do is:
int i=0; //Value of i will change as I want to use it in loop
string name="c"+i;
double a= name[i]; //The real name of arrays I have declared are: c0[],c1[] etc
It gives error: "Project" does not contain a definition for "name"
So, How do I acheive this?
Obviously you have a set of variables, all sharing a common name, e.g. MyVariable1, MyVariable2, etc.
Instead of having so many similar variables, you should use an array, or in your case an array of arrays:
var myVariableArray = new double[][] { c[0], c[1], ... };
Now you can easily acces the i-th number within that array:
double a = myVariableArray[i][i];
Alternativly if those variables actually are members (fields or propertiers) within your class, you can also use reflection to get the right member from a string:
var fields = typeof(MyType).GetField(name + i);
double b[];
if(field != null)
b = (double[]) field.GetValue(instanceOfMyType, null);
else
{
var prop = typeof(MyType).GetProperty(name + i);
if(prop != null)
b = (double[]) prop.GetValue(instanceOfMyType, null);
}
a = b[i];
However such a data-structure is bad design, you should go with an array (or list) of members, instead of having dozens of similar members.
You need an array of arrays (two-dimensional arrays), don't you?
To create an array of arrays, do this:
double[][] twoDArray = new double[][x];
where x is the number of arrays you want.
Now you can populate it with some arrays like this:
twoDArray[0] = new double[] {1.0, 1.1, 1.2};
twoDArray[1] = new double[] {7.7, 8.8, 9.9};
To access an array in the 2D array, you don't even need name, you just use i directly!
double[] oneOfTheArrays = twoDArray[i];
double a = oneOfTheArray[0];
Or more simply:
double a = twoDArray[i][0];

Update a variable inside ForEach loop

I simply can't understand why this simple code is not working. My expected output is 10 and 15, but it is returning 2 and 3. That means that the update is not working.
List<int> numbers = new List<int>();
numbers.Add(2);
numbers.Add(3);
numbers.ForEach(n => n = n*5);
numbers.ForEach(n => Console.WriteLine(n));
Note: I've already searched a lot, but I could not understand this behavior.
How should I fix it?
Update: the same behavior for strings.
List<string> strings = new List<string>();
strings.Add("a");
strings.Add("b");
strings.ForEach(s => s = s + "--");
strings.ForEach(s => Console.WriteLine(s));
n is a copy of your current value in the list not a reference to your value.If you want to manipulate the values in your list then use a for loop
for(int i = 0; i<numbers.Count; i++)
numbers[i] *= 5;
More detailed explanation:
With a normal foreach loop your code doesn't even compile:
foreach(var n in numbers)
n = n * 5; // Readonly local variable cannot be used as an assignment target
Remember that List<T>.ForEach loop is not the same as foreach but it is just a method that takes a Action<int> delegate as argument and performs the specified action on the each element in your list.So it performs something like this (taken from the source code):
public void ForEach(Action<T> action)
{
// removed unnecessary parts for brevity
for(int i = 0 ; i < _size; i++)
{
action(_items[i]);
}
}
As you can see here the _item[i] is passed to the action and since int is a value types the copy of your value is passed rather than a reference.And that's why your values didn't change.
For strings: Apart from the fact that strings are immutable, assigning a new reference to a reference type doesn't change the object that holds the same reference.For example consider this:
static void Update(string s)
{
s = "bar";
}
string f = "foo";
Update(f);
Console.WriteLine(f); // foo
Assigning a new reference to s doesn't change the f, f stil holds the old reference and s is pointing to a new location in memory.This is not because s is a copy,it's not.If you change a property of s (with strings you can't do that but try with another reference type), it would update the property of f as well.It works in this way because s and f are two different strings that points to the same location in memory.So s is not bound to f.You can think they were declared like this:
string f = "foo";
string s = f;
s = "bar";
The only exception is when you pass f as a ref argument then the assignment will change the f as well:
static void Update(ref string s)
{
s = "bar";
}
string f = "foo";
Update(ref f);
Console.WriteLine(f); // bar
Because they are value types, rather than mutating the list you could create a modified one using Select
var newList= numbers.Select(n => n = n*5);
As imperative programmers, we love mutating things, which is not a brilliant idea!!
The reason why it did not work for strings is that because by default C# passes a copy of the reference rather than the actual reference.
void Fn(string s)
{
s = "not being changed";
}
Main()
{
var hello = "hello";
Fn(hello);
Console.WriteLine (hello); // prints hello again!!
}
However, if you want to change the reference you have to use the ref keyword.
void Fn(ref string s)
{
s = "Unfortunately, changed!";
}
Main()
{
var hello = "hello";
Fn(ref hello);
Console.WriteLine (hello); // Unfortunately, changed!!!
}
I think that changing parameters' values is a terrible idea and you shouldn't be doing that, you should return a new string that contains the new modifications.
The reason is because the parameter to the ForEach are passed by value and not by reference.
However, if you do pass a reference type, it must work as expected as shown below
class Program
{
static void Main(string[] args)
{
List<Frog> numbers = new List<Frog>();
numbers.Add(new Frog { name = "balcha" });
numbers.Add(new Frog { name = "Tibara" });
numbers.ForEach(n => n.name = "Bontu");
numbers.ForEach(n => Console.WriteLine(n.name));
Console.ReadLine();
}
class Frog
{
public string name { get; set; }
}
}
Output:
Bontu
Bontu

Do synonyms exist?

Is there a way to have a variable set to an object and have another variable which is always equals to the former one?
var x = new object();
var y = [synonym of x];
x = null; // then y = null as well
I don't think this exists.
So I've often used arrays to hold "references".
var x = new object[] { new object() };
var y = x;
x[0] = null; // then y[0] = null as well
But it feels kinda lame.
If you really really need to this you can do something like below but I think it is still lame (:
class RefHolder<T>
{
public RefHolder(T value)
{
Value = value;
}
public T Value { get; set; }
}
Usage
var o1 = new RefHolder<object>(new object());
var o2 = o1;
o2.Value = null; // now o1.Value is null too
You can do it but the price you have to pay is to use undocumented keywords/features. They're there from long time ago and probably they won't change or disappear but...
It'll make your code more complicated to read (it may be useful if supported by the language itself) but it's bidirectional and you can move around your original object, changes will always be reflected to your "reference" too. It differs from Mehmet Ataş answer because you can pass the original object to another function and changes will propagate to your synonym too. They have limitations (they can't be used for class fields) but they works for parameters and local variables.
What you need is a TypedReference, it holds a reference to another variable then if you assign a new value to it you'll change the original variable. This in theory could open the door to synonyms if someday they'll think it's a good feature to include.
Let's see an example:
var text = "initial value";
var synonym = __makeref(text);
Now synonym is a reference to text (please note it's a reference to text and not to the value it holds). To get original value from a TypedReference you use __refvalue like this:
Console.WriteLine(__refvalue(synonym, string));
They have the same value:
Debug.Assert(__refvalue(synonym, string) == text);
Now let's change text to a new value:
text = "second value";
Debug.Assert(__refvalue(synonym, string) == text);
And even opposite is true:
__refvalue(synonym, string) = "third value"; // <---
Debug.Assert(__refvalue(synonym, string) == text);
Finally let's modify the original variable within another function (unaware of the reference it'll see a normal variable):
void ChangeIt(ref string value) { value = "another value"; }
ChangeIt(ref text);
Debug.Assert(__refvalue(synonym, string) == text);
All of this works will value types as well. Note that this creates a synonym for a variable, not an alias (you can imagine them as a safe pointer - to pointer in case of reference type). Let's try this:
void foo1()
{
string text = "ABC";
foo2(text);
// text holds the original value "ABC"
// not the value modified in foo2
}
void foo2(string value)
{
value = "123";
var synonym = __makeref(value);
__refvalue(value, string) = "456";
// both value and synonym holds "456";
}
Well, you are basicly describing a C++ reference (or a C pointer).
This can be done in C#, too, but you REALLY do not want to do this unless you absolutely need to.
unsafe static void Main(string[] args)
{
int a = 5;
int *b = &a;
*b = 0;
Console.WriteLine(a);
}
This will output 0 to the console.
You can read more about unsafe code in Unsafe Code and Pointers article on MSDN.
It depends. .NET contains both Reference and Value types. Value types are all the basic types, int, bool etc.. plus string. Reference types are everything else, including anything you create for yourself.
So, for example, value types...
int a = 3;
int b = a;
b = 5;
// a is still 3
While with references
class Mine {
public int A { get; set; }
}
Mine A = new Mine() { A = 3; }
Mine B = A;
B.A = 5;
// A.A is now 5.
you can asign like
var parentObject={};
parentobject['child1']="test1";
parentobject['child2']="test2";
parentobject['child3']="test3";
after
console.log(parentObject);
you get following output
object{child1="test1",child2="test2",child2="test2"}

Categories

Resources