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
Related
i am new to c# and i have been trying to make a string[] that changes its contents depending on the int value of a different variable. i've tried switches and ifs but when i try to call the variable afterwards the program states that the variable does not exist in current context.
Im sorry for the bad description but here's a sample code regarding what i mean.
int flag = 0; //Value Changes
if (flag == 1)
{
string[] mainoptions = {"Return"};
}
else if (flag == 0)
{
string[] mainoptions = { "Grab Shovel", "Return" };
}
WriteLine(mainoptions); //The name 'mainoptions' does not exist in current context
For the vast majority of cases, any variables (eg. string name; or string name = "Roger";) that are created inside curly braces { } can only be accessed using their identifier from inside those braces.
Take this example:
int a = 0;
if (condition)
{
int b = 1;
}
Console.WriteLine(a); // can see the 'a' variable -> works fine
Console.WriteLine(b); // can NOT see the 'b' variable -> compilation error
The variable a can be accessed from the "main scope" (for lack of a better term), and also inside the if statement because the if statement defines a sub-scope, per se.
Variable b however, can only be accessed from within the if statement it was declared in, and also any sub-scopes that might occur inside there. It can NOT be accessed outside that if statement, because as soon as the program exits the block (reaches the closing brace }) you can imagine that variable b's reference is deleted.
With that, you can edit your program to define the variable mainoptions outside the if statements, and that will solve your issue
Let's get to the bottom of this:
You didn't declare a variable/property behind the if-construction. Anything that is declared in a logical construct does not exist for the compiler behind it. You've probably seen this before in the "access level" here: link.
If you want to print the variable array in a logical construct, you should do it like this:
if (a == someValue1)
{
string[] b = { "Return" };
System.Console.WriteLine(b);
}
else if (a == someValue2)
{
string[] b = { "Grab Shovel", "Return" };
System.Console.WriteLine(b);
}
But there's a mistake here: you can't assign something to an array just in curly braces { }, you have to declare it correctly:
string[] arr; // array is not initialized
arr = new string[] { "text", "text", "text" } // the array is now initialized
But that's not really convenient and the code gets bloated, so you should define this variable before the logical construct:
string[] b = new string[] { };
if (a == someValue1)
{
b = new string[] { "Return" };
}
else if (a == someValue2)
{
b = new string[] { "Grab Shovel", "Return" };
}
System.Console.WriteLine(b);
That's more convincing, isn't it?
Now let's think what we can improve here...
The flag variable is of type int, but it takes 0 and 1, which is more like a bool, so let's make it a bool.
Flag can still be made a property to make it easier to use, let's do that!
Let's replace if-else with a switch-case, so there are no unnecessary checks.
And we get the following:
class Program
{
public static bool Flag { get; set; }
public static void Main(string[] args)
{
string[] mainoptions = new string[] { };
Flag = false;
switch (Flag)
{
case true:
mainoptions = new string[] { "Return" };
break;
case false:
mainoptions = new string[] { "Grab Shovel", "Return" };
break;
}
foreach (var option in mainoptions)
System.Console.WriteLine(option);
}
}
Oh, did you also notice that I printed the result differently, and there is a new foreach construct?
foreach (var option in mainoptions)
System.Console.WriteLine(option);
Well, you can't just print the array because you just get its type, not its content. To print the whole array, we have to go through it from index 0 to the end, printing out every value.
You can address the array using the index:
var arr = new int[] { 1, 2, 3, 4 };
Console.WriteLine(arr[0]); // => print 1
Let's make it even cooler, shall we? We use a ternary operator, it's an analogue of if-else when we only have 2 execution paths:
class Program
{
public static bool Flag { get; set; }
public static void Main(string[] args)
{
string[] mainoptions = new string[] { };
Flag = false;
mainoptions = Flag ? new string[] { "Return" } : new string[] { "Grab Shovel", "Return" };
foreach (var option in mainoptions)
System.Console.WriteLine(option);
}
}
I hope this will be useful! Have a nice day!
so what i have learned you can use a If to check a var! you can also use a switch statement witch are super useful!
int Flag = 0;
String mainoptions;
Static void Main()
{
switch(Flag)
{
case 1:
// case means the if this is the var then run this block of code.
// the 1 is the int number so if we put 100 in the place of the 1 then the switch statment would check if the var (Flag) is 100. and if it the code just moves on. you can add whatever you want in the case 1. so if you wanted your string to be "Example" if the int Flag was 1 then you would put:
mainoptions = "mainoption's";
// you can as as many cases as you want as well.
Brake;
}
}
also your mainoptions does not exist bc its a temp var. your int Flag works bc its outside of the method AKA in the class. so in other words you cant use temp vars outside of the method it is put into or initialised in.
Outside of implementing collections yourself, arrays are generally a poor choice for storing a collection of objects. Consider instead using List<string>:
int flag = 0; //Value Changes
var mainOptions = new List<string>{
"Return"
};
if (flag == 0)
{
mainoptions.Insert(0,"Grab Shovel");
}
WriteLine(mainoptions);
(If WriteLine is your own method, you may have to change its signature to accept List<string> instead of string[] and there may be further cascading changes)
Part of what makes arrays awkward to work with is that they have a fixed number of elements. But you're already working in a scenario where you want to easily change the number of elements. So use a type that makes that easy to do.
I am trying to call a function which returns a tuple with two arrays. The content of the arrays are based on checked items in a checkedListBox.
I define the arrays and call the function "storeParametersInArrays" as shown below.
string[] allowedObjects = new string[checkedListObjects.CheckedItems.Count]; // All allowed objects
string[] notallowedObjects = new string[checkedListObjects.Items.Count - checkedListObjects.CheckedItems.Count]; // All not allowed objects
Tuple<string[], string[]> ObjParameters = storeParametersInArrays(notallowedObjects, allowedObjects, checkedListObjects);
allowedObjects = ObjParameters.Item1;
notallowedObjects = ObjParameters.Item2;
The function called is defined as:
private Tuple<string[], string[]> storeParametersInArrays(string[] notallowed, string[] allowed, CheckedListBox checkedListBox)
{
int i = 0; // allowed objects
int j = 0; // not allowed objects
int k = 0; // item counter
foreach (object item in checkedListBox.Items)
{
if (!checkedListBox.CheckedItems.Contains(item))
{
notallowed[j++] = checkedListBox.Items[k].ToString();
}
else
{
allowed[i++] = checkedListBox.Items[k].ToString();
}
k++;
}
return Tuple.Create<allowed, notallowed>;
}
I am unable to return the Tuple in the above code sample. I get the error "Cannot convert method group 'Create' to non-delegate type 'Tuple'".
It is my first time working with tuples, how can I return the two arrays without having to call the function twice?
I have looked at slightly similar problems, so if the question is already answered somewhere else, I will be glad to be pointed in the right direction.
Just change
return Tuple.Create<allowed, notallowed>;
to
return Tuple.Create(allowed, notallowed);
The first syntax is for generics: <
The second for method calls: (
You have to correct your method call Tuple.Create:
private Tuple<string[], string[]> storeParametersInArrays(string[] notallowed, string[] allowed, CheckedListBox checkedListBox)
{
int i = 0; // allowed objects
int j = 0; // not allowed objects
int k = 0; // item counter
foreach (object item in checkedListBox.Items)
{
if (!checkedListBox.CheckedItems.Contains(item))
{
notallowed[j++] = checkedListBox.Items[k].ToString();
}
else
{
allowed[i++] = checkedListBox.Items[k].ToString();
}
k++;
}
return Tuple.Create(allowed, notallowed);
}
This line
return Tuple.Create<allowed, notallowed>;
replace with
return Tuple.Create<string[], string[]>(allowed, notallowed);
Or simple
return Tuple.Create(allowed, notallowed);
The static method Create is a generic method and the error is that you are using the values like the types that the Create method will return.
You placed the values where the type parameters should be. But I think that the type parameters can be inferred here:
return Tuple.Create(allowed, notallowed);
However, you could use new ValueTuples. A simplified tuple syntax was introduced in C# 7.0.
private (string[], string[]) storeParametersInArrays(
string[] notallowed, string[] allowed, CheckedListBox checkedListBox)
{
...
return (allowed, notallowed);
}
You can then get the result stored directly into your existing variables with:
(allowedObjects, notallowedObjects) = storeParametersInArrays(
notallowedObjects, allowedObjects, checkedListObjects);
But since arrays are reference types, you don't even have to return them from the method. You are not passing copies of the arrays to the method - only references. Therefore the method fills the original arrays.
private void storeParametersInArrays(
string[] notallowed, string[] allowed, CheckedListBox checkedListBox)
{
// Fill the arrays here.
// No need for a return statement.
}
Now you can write
storeParametersInArrays(notallowedObjects, allowedObjects, checkedListObjects);
// allowedObjects and notallowedObjects are now filled. Example
string firstAllowed = allowedObjects[0];
You can even go a step further and use the Local functions introduced in C# 7.0. They have access to the variables of the surrounding method and therefore don't require the parameters in this case.
void myButton_Click(object sender, RoutedEventArgs e)
{
string[] allowedObjects = new string[...];
string[] notallowedObjects = new string[...];
storeParametersInArrays();
// Use the result
string firstAllowed = allowedObjects[0];
// Nested local function
void storeParametersInArrays()
{
// You can access allowedObjects, notallowedObjects and checkedListObjects here.
// Fill the arrays.
}
}
I have a class which should be immutable in this class i have only get indexer a private set property so why this is not immutable and i can set some field in array as you could see in main class...
class ImmutableMatice
{
public decimal[,] Array { get; private set; } // immutable Property
public ImmutableMatice(decimal[,] array)
{
Array = array;
}
public decimal this[int index1, int index2]
{
get { return Array[index1, index2]; }
}
........
and in main method if i fill this class with data and change the data
static void Main(string[] args)
{
decimal[,] testData = new[,] {{1m, 2m}, {3m, 4m}};
ImmutableMatice matrix = new ImmutableMatice(testData);
Console.WriteLine(matrix[0,0]); // writes 1
testData[0, 0] = 999;
Console.WriteLine(matrix[0,0]); // writes 999 but i thought it should
// write 1 because class should be immutable?
}
}
Is there any way how to make this class immutable?
Ah yes the solution was copy array to new array in constructor like this:
public ImmutableMatice(decimal[,] array)
{
decimal[,] _array = new decimal[array.GetLength(0),array.GetLength(1)];
//var _array = new decimal[,] { };
for (int i = 0; i < array.GetLength(0); i++)
{
for (int j = 0; j < array.GetLength(1); j++)
{
_array[i, j] = array[i, j];
}
}
Array = _array;
}
That is because you are actually changing the data in the ARRAY, rather than the indexer.
static void Main(string[] args)
{
decimal[,] testData = new[,] {{1m, 2m}, {3m, 4m}};
ImmutableMatice matrix = new ImmutableMatice(testData);
Console.WriteLine(matrix[0,0]); // writes 1
testData[0, 0] = 999; // <--- THATS YOUR PROBLEM
Console.WriteLine(matrix[0,0]); // writes 999 but i thought it should
// write 1 because class should be immutable?
}
You can copy the array into your private property in the constructor to avoid this situation.
Note that you indeed cannot write matrix[0,0] = 999; because the indexer has no setter.
Edit
As Chris pointed out (how could I have missed it myself?) - you shouldn't expose the array as a property at all (which means in most cases it doesn't even have to be a property).
Consider the following code instead:
private decimal[,] _myArray; // That's private stuff - can't go wrong there.
public decimal this[int index1, int index2]
{
// If you only want to allow get data from the array, thats all you ever need
get { return Array[index1, index2]; }
}
Your class is immutable, but the objects inside it aren't.
Having public decimal[,] Array { get; private set; } will only guarantee that you cannot set the property Array to a new instance of Array, but it does not prevent you from accessing the existing object and changing its values (which aren't immutable).
You might want to look into the appropriately named ReadOnlyCollection<T> class.
As #Mike pointed out and I looked past the first time: there's a twist to this because you are accessing the value through the testData object and not through matrix. While the original point still stands, it is more exact to say that the problem you have is that you are changing values in the underlying object which has its reference passed around. You're bypassing the ImmutableMatice object alltogether.
The beforementioned solution of using a ReadOnlyCollection<T> still stands: by creating this read-only wrapper around it, you won't be able to change it anymore afterwards. Howver this is only the case when you actually use it the way its intended: through ImmutableMatice and not through the underlying collection which you still have a reference to.
Another solution that solves this problem is to copy the contents of the original array to another one to "disconnect" it from the array your still have a reference to.
In order to illustrate this, consider the following samples. The first one demonstrates how the underlying reference can still be influenced while the second one shows how it can be solved by copying your values to a new array.
void Main()
{
var arr = new[] { 5 };
var coll = new ReadOnlyCollection<int>(arr);
Console.WriteLine (coll[0]); // 5
arr[0] = 1;
Console.WriteLine (coll[0]); // 1
}
void Main()
{
var arr = new[] { 5 };
var arr2 = new int[] { 0 };
Array.Copy(arr, arr2, arr.Length);
var coll = new ReadOnlyCollection<int>(arr2);
Console.WriteLine (coll[0]); // 5
arr[0] = 1;
Console.WriteLine (coll[0]); // 5
}
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"}
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