I want to set a value for array item variable:
string string1;
string string2;
string[] myArray = { string1, string2 };
public Test(){
for(int i=0; i < myArray.Length; i++){
myArray[i] = "hello!";
}
}
If I use myArray[i] = "Hello" method, then it sets to myArray value not string1 and string2 value.
An array in C# contains primitive values (integers, doubles, booleans, …) or references (references to class or struct instances). When you update one item of the array, you are only changing the "value" in the array. You are not updating thte object being pointed to. In other words: you are only swapping the reference to point to a different object, the object is never changed.
To achieve this, you need to insert another level of inderection (think pointer to pointer in good ol' C).
One option to achieve this would be to introduce a wrapper type to hold your value and allow to update it:
class Reference<T> {
T Value { get; set; }
public Reference(T value) {
this.Value = value;
}
}
Reference<string> string1;
Reference<string> string2;
Reference<string>[] myArray = { string1, string2 };
public Test() {
for(int i = 0; i < myArray.Length; i++) {
myArray[i].Value = "hello!";
}
}
you need to initialize the empty string for "string1" & "string2". then it will take the value in it.
string string1="";
string string2="";
string[] myArray = { string1, string2 };
for (int i = 0; i < myArray.Length; i++)
{
myArray[i] = "hello!";
}
You cannot change variables string1 and string2 by manipulating the array.
I hope the following snippet makes it clearer what happens. The important part is that when the array is created it contains references to the objects that the variables point to, not to the variables themselves. a[i] = changes what the array element points to, not what variable it was created from.
// Int is a value type
int i1 = 1;
int[] ai = { i1 }; // the array contains the actual number '1',
// each element of the array is the size of int
ai[0] = 7; // This swaps number 1 to 7 *inside* the array
// C is a class which is a reference type
C c = new C { Property = 1 };
C[] a2 = { c }; // the array contains the reference to 'c'
// Now both c and a2[0] point to the same object
// Importantly, c doesn't control the array
// and the array doesn't control variable c
// They just point to the same object
a2[0].Property = 2; // This changes Property of the object a2 points,
// which is the same object c points to
// Please note that c.Property = 3; would not change the array,
// it would change the object that a[0] also points to.
// However, we can also change what object a[0] points too;
a2[0] = new C { Property = 4 }; // This makes a[0] point to a new object
// In C# string is a reference type
string string1 = "Hello1";
string[] myArray = { string1 };
myArray[0] = "hello!"; // This makes myArray[0] point to another object and that object is a new string "hello!"
I am not exactly sure what you're asking but I think your confusion is about reference and value types.
If you want to write to string1 and string2 using myArray you have to know a thing or two about value and reference types in C#.
For your current usage you can consider string a value type. With this I mean: that if you assign a string to another string (string stringX = a_previous_declared_String) it creates a copy. Changing the copy will not change the original. Storing your string in MyArray also creates a copy.
(Please note that in fact string is a reference type which behaves like a value type when doing assignment (stringX = stringY) operations. If you want to know more, you can e.g. start here. For the purpose of explaining the general difference between value types and reference types, using your example, I simplify an call string a value type here).
If you want to change the original, you have to store a reference to your string in myArray. For this, in C#, you can create a reference type variable which holds your value type. This can be a class which holds your string as a field. Then, you store a reference to your class in MyArray. If you then change the string via MyArray, your original string1 and string2 wil also get modified.
I created the simplest version of this to help you understand. See #knittl his answer for a more general implementation that would work for other value types (like int and float) as well.
My example (which I tested and runs as C# console application):
using System;
namespace TestProgram
{
public class RefTypeString
{
public string MyString;
public RefTypeString(string myString)
{
MyString = myString;
}
}
class Program
{
static void Main(string[] args)
{
RefTypeString string1 = new RefTypeString(null);
RefTypeString string2 = new RefTypeString("initial value");
RefTypeString[] myArray = { string1, string2 };
for (int i = 0; i < myArray.Length; i++)
{
if (i == 0)
{
myArray[i].MyString = "hello!"; //set value for string1 and string2 not an array
}
}
Console.WriteLine("MyArray[0] / string1");
Console.WriteLine(myArray[0].MyString);
Console.WriteLine("MyArray[1] / string1");
Console.WriteLine(myArray[1].MyString);
Console.WriteLine("string1");
Console.WriteLine(string1.MyString);
Console.WriteLine("string2");
Console.WriteLine(string2.MyString);
}
}
}
Console output:
MyArray[0] / string1
hello!
MyArray[1] / string1
initial value
string1
hello!
string2
initial value
Related
I have trouble with the value that arraylist returns.
I created a two-dimensional Arraylist that includes string arrays, when I try to get actual value of string arrays, I get System.String[] as output
instead of actual value of the arrays.
Why do I get System.String() as outuput?
Here is my code :
static void Main(string[] args)
{
string[] employee_1 = { "Employee1" };
string[] employee_2 = { "Employee2" };
ArrayList main_array = new ArrayList();
main_array.Add(employee_1);
main_array.Add(employee_2);
for (int i= 0; i < 2; i++)
{
Console.WriteLine(main_array[i]);
}
Console.ReadKey();
}
That is because when retrieving the items from an ArrayList what you are getting is a reference to an object instead of the actual type. Thus when printing it is calls the ToString of object (which prints the type's name) and not the string you want. In addition when printing a collection (like you are doing in your WriteLine command) you need to specify how to so do because it's default implementation is also as object's. You can use string.Join to print all items in the nested array.
To correct this first cast to string[] ( as string[]) and then print, or better still is to work with the list object instead: List<string[]>. To read more see:
ArrayList vs List<> in C#
What is the difference between an Array, ArrayList and a List?
So:
var mainCollection = new List<string[]> { new string[] { "Employee1" },
new string[] { "Employee2" }};
for (int i = 0; i < mainCollection.Count; i++)
{
Console.WriteLine(string.Join(", ", mainCollection[i]));
}
Console.ReadKey();
As a side note do not loop to 2 but instead by the number of items in the collection. See: What is a magic number, and why is it bad?
This is the default behaviour of ToString() function for an array.
To print the employees names, you need to iterate the array:
for (int i= 0; i < 2; i++)
{
foreach(string employee in main_array[i]) {
Console.WriteLine(employee);
}
}
The problem is here, ArrayList always take input as an object. So, when you add string array at an ArrayList, it take an object instead of string array.
So, you should convert this object to string array and print it.
like below:
for (int i = 0; i < 2; i++)
{
Console.WriteLine(string.Join(", ", main_array[i] as string[]));
}
or may use below(both are same):
for (int i = 0; i < 2; i++)
{
foreach (string employee in main_array[i] as string[])
{
Console.WriteLine(employee);
}
}
Because you have string[] type elements in outer ArrayList.
The best examples to enumerate are in answers above. If you realy need string content of string to be wtitten you should use
Console.WriteLine(((string[])main_array[i])[0]);
main_array is a two position ArrayList, each position contains a string[] this is, a string array.
If you use main_array[0], this is a reference to employee_1 which is a string array.
You should be able to reference the array strings by using main_array[0][0]
Try this:
foreach(var strArray in main_array)
{
// strArray is a string array
foreach(var stir in strArray)
{
// star is a string
Console.WriteLine(str);
}
}
I am having an issue with C# function argument passing.
I was wondering how would I make a C# function accept a parameter by value (to make a copy of the original object).
I thought that was the default way C# handled these things, but in the following code:
using System;
using System.Collections.Generic;
using System.Linq;
class MaximumElement
{
static void Main(string[] args)
{
Stack<int> numbers = new Stack<int>();
int n = int.Parse(Console.ReadLine());
for (int i = 0; i < n; i++)
{
string input = Console.ReadLine();
switch (input)
{
case "2": numbers.Pop(); break;
case "3": Console.WriteLine(maxElement(numbers)); break;
default:
string[] argz = input.Split(' ');
numbers.Push(int.Parse(argz[1]));
break;
}
}
}
public static int maxElement(Stack<int> stack)
{
int max = stack.Peek();
for (int i = 0; i < stack.Count; i++)
{
if (max >= stack.Peek())
{
stack.Pop();
}
else if (max < stack.Peek())
{
max = stack.Pop();
}
}
return max;
}
}
My maxElement() function actually changes the original stack I pass to it, and the only way to get around it is to manually make a copy of the stack I pass to the function inside the function.
Thanks for any responses in advance :)
Don't mix passing arguments by value or reference with value types and reference types. Its a common beginner's mistake and you need to have a clear understanding of how both things, allthough related in some way, are completely different features of the language.
I'll probably not use precise terminology because english is not my language but I hope I can get the idea across:
Value type: The variable is the value itself. When you write the following: int i = 1; the variable i holds the value 1.
Reference type: The variable is a reference that points to a place in memory where the object is. That means that, when you say string s = "Hello"; s does not contain "Hello", it contains the memory address where "Hello" is stored.
So what happens when you pass an argument by value (default in C#). We have two possibilities:
Argument is a value type: You get a copy of the variable, that means
that if you pass along i = 1 you recieve a copy which also
contains 1, but both are alltogether different objects.
This is obvious when dealing with mutable value types, for example System.Drawing.Point:
Point point = new Point(0, 0);
Frob(point);
var b = point.X == 1 && point.Y == 1; //False, point does not change.
void Frob(Point p) { p.Offset(1, 1); } // p is a copy of point and therefore contains a copy of the value stored in point, not the value itself.
Argument is a reference type: You get a copy of the variable, that means you get a copy of the reference to the memory address, but the object the copy is pointing at is the same. This is the scenario you are in.
Foo foo = new Foo();
foo.Blah = 1;
Frob(foo);
var b = foo.Blah == 2; //True, foo.Blah has been modified.
void Frob(Foo f) { foo.Blah = 2; } //both foo and f point to the same object.
Notice that in both cases what you can't do is modify what the reference is pointing to. This won't work:
string s = "hello";
foo(s);
var b = s == "bye"; //false, s still points to the original string
void Foo(string str)
{
str = "bye";
}
Now, what happens if we pass by reference? Well, the main difference is that you are passing the variable itself, not a copy. That means that in case of a value type you are passing the original value and in case of a reference type, the original address, not a copy. This allows the following:
//Value type
Point point = new Point(0, 0);
Frob(ref point);
var b = point.X == 1 && point.Y == 1; //True, point and p are the same variable.
void Frob(ref Point p) { p.Offset(1, 1); }
and
//Value or reference type
string s = "hello";
foo(ref s);
var b = s == "bye"; //true
void Foo(ref string str)
{
str = "bye";
}
Hope this clarifies the difference.
It is a little complex. From MSDN (https://msdn.microsoft.com/en-us/library/s6938f28.aspx):
A variable of a reference type does not contain its data directly; it contains a reference to its data. When you pass a reference-type parameter by value, it is possible to change the data pointed to by the reference, such as the value of a class member. However, you cannot change the value of the reference itself; that is, you cannot use the same reference to allocate memory for a new class and have it persist outside the block. To do that, pass the parameter using the ref or out keyword. For simplicity, the following examples use ref.
Here is the code example they provide:
static void Change(int[] pArray)
{
pArray[0] = 888; // This change affects the original element.
pArray = new int[5] {-3, -1, -2, -3, -4}; // This change is local.
Now, if you use the ref keyword on your parameter
static void Change(ref int[] pArray)
{
pArray[0] = 888; // This change affects the original element.
pArray = new int[5] {-3, -1, -2, -3, -4}; // This change also affects the original
So, with those things in mind, you could...
public static int maxElement(Stack<int> stack)
{
stack = new Stack<int>(stack); // Now changes will be local
int max = stack.Peek();
for (int i = 0; i < stack.Count; i++)
{
if (max >= stack.Peek())
{
stack.Pop();
}
else if (max < stack.Peek())
{
max = stack.Pop();
}
}
return max;
}
You would need to make a copy of the Stack, which if a shallow copy works you can use Clone() method.
In the main program class I have:
static void Main()
{
string[,,] anArray = new string [3,3,3];
anArray[0,0,0] = "value1";
anArray[0,0,1] = "value2"; .... //filling the rest of the array.
}
How can I pass this array into another separate class "anotherClass" using a constructor with multiple arguments like:
class AnotherClass
{
private string[,,] anotherClassArray;
public string[,,] AnotherClassArray
{
get { return anotherClassArray;}
}
public AnotherClass (string[,,] fromAnArray)
{
anotherClassArray = new string [fromAnArray.Length];
}
}
I've seen examples with just a simple 1 dimensional array being passed from the Main program into another separate class and back again but when I tried following the same example for a multidimensional I get the error:
"Cannot implicitly convert type 'string[]' to 'string[,,*]'" when trying to initialize the new array.
If you want AnotherClass to have it's own separate, empty, instance of a 3D array, then you can do what Pikoh said. In this case, if you change the contents of the array, the original array created in Main is unaffected, and vice versa.
If you want AnotherClass to reference the same array as the one created in Main, and therefor have access to it's same, filled in contents, then simply set the AnotherClass.anotherClassArray reference to equal fromAnArray in the AnotherClass constructor like so:
public AnotherClass (string[,,] fromAnArray)
{
anotherClassArray = fromAnArray;
}
You can do it like this:
string[, ,] anotherClassArray = new string[anArray.GetLength(0),
anArray.GetLength(1),
anArray.GetLength(2)];
Update
As a experiment, if you want make this to generic for any unknown number of dimensions, you can use this method:
private Array CreateArrayWithSameDimensions(Array inArray)
{
int[] lengths = new int[inArray.Rank];
for (int i = 0; i < inArray.Rank; i++)
{
lengths[i] = inArray.GetLength(i);
}
Array myArray = Array.CreateInstance(typeof(string), lengths);
return myArray;
}
The problem with this approach is that accessing this array is not as simple as with known dimensions. This is an example of usage:
Array myArray = CreateArrayWithSameDimensions(anArray);
int[] indices = new int[anArray.Rank];
for (int i = 0; i < anArray.Rank; i++)
{
indices[i] = 0;
}
myArray.SetValue("test", indices);
This would set test in the lower bound index of that array. If the input array was a 3 dimensional array, in myArray[0,0,0] we would have test.
I'm learning about Indexers and stumble across the explanation and example of the tutorial I'm reading.
It says:
"An indexer allows an object to be indexed such as an array. When you define an indexer for a class, this class behaves similar to a virtual array. You can then access the instance of this class using the array access operator ([ ])"
What I understand with this paragraph is that you can access an instance of that class using the array access operatos.
But what I really dont understand of this explanation is the following:
"Declaration of behavior of an indexer is to some extent similar to a property. similar to the properties, you use get and set accessors for defining an indexer. However, properties return or set a specific data member, whereas indexers returns or sets a particular value from the object instance. In other words, it breaks the instance data into smaller parts and indexes each part, gets or sets each part".
I dont get the "It breaks the instance data into smaller parts and indexes each part"
After this it gives an example of Indexer:
using System;
namespace IndexerApplication
{
class IndexedNames
{
private string[] namelist = new string[size];
static public int size = 10;
public IndexedNames()
{
for (int i = 0; i < size; i++)
namelist[i] = "N. A.";
}
public string this[int index]
{
get
{
string tmp;
if( index >= 0 && index <= size-1 )
{
tmp = namelist[index];
}
else
{
tmp = "";
}
return ( tmp );
}
set
{
if( index >= 0 && index <= size-1 )
{
namelist[index] = value;
}
}
}
static void Main(string[] args)
{
IndexedNames names = new IndexedNames();
names[0] = "Zara";
names[1] = "Riz";
names[2] = "Nuha";
names[3] = "Asif";
names[4] = "Davinder";
names[5] = "Sunil";
names[6] = "Rubic";
for ( int i = 0; i < IndexedNames.size; i++ )
{
Console.WriteLine(names[i]);
}
Console.ReadKey();
}
}
}
Before that paragraph I thought Indexers where a form to index and instance of that class as an array, but that "smaller parts" I really dont understand.
It's really just giving an example of the use of an indexer. Returning an element from the array is, in a way, returning part of the array.
But it needn't be an array. For example, String has an indexer which returns the character at that position, e.g. "test"[0] returns the character in position zero, which is 't'.
Other objects may have other indexers which do other things. For example a DataTable DataRowCollection has an indexer which returns rows by number, and which has an indexer which returns columns by name:
myDataTable.Rows[12]["ID"].Value
I'm coming from a C++ background. This question has been asked before, but try as I might I cannot find the answer. Let's say I have:
string[] ArrayOfReallyVeryLongStringNames = new string[500];
ArrayOfReallyVeryLongStringNames[439] = "Hello world!";
Can I create a string that references the above (neither of these will compile):
string a = ref ArrayOfReallyVeryLongStringNames[439]; // no compile
string a = &ArrayOfReallyVeryLongStringNames[439]; // no compile
I do understand that strings are immutable in C#. I also understand that you cannot get the address of a managed object.
I'd like to do this:
a = "Donkey Kong"; // Now ArrayOfReallyVeryLongStringNames[439] = "Donkey Kong";
I have read the Stack Overflow question Make a reference to another string in C#
which has an excellent answer, but to a slightly different question. I do NOT want to pass this parameter to a function by reference. I know how to use the "ref" keyword for passing a parameter by reference.
If the answer is "You cannot do this in C#", is there a convenient workaround?
EDIT:
Some of the answers indicate the question was unclear. Lets ask it in a different way. Say I needed to manipulate all items in the original long-named array that have prime indices. I'd like to add aliases to Array...[2], Array...[3], Array...[5], etc to a list. Then, modify the items in the list using a "for" loop (perhaps by passing the list just created to a function).
In C# the "using" keyword creates an alias to a class or namespace. It seems from the answers, that it is not possible to create an alias to a variable, however.
You could create a wrapper that keeps a reference to the underlying array AND the index of the string:
public sealed class ArrayStringReference
{
private readonly string[] _array;
private readonly int _index;
public ArrayStringReference(string[] array, int index)
{
_array = array;
_index = index;
}
public string Value
{
get
{
return _array[_index];
}
set
{
_array[_index] = value;
}
}
public override string ToString()
{
return Value;
}
}
Then this will work:
string[] ArrayOfReallyVeryLongStringNames = new string[500];
ArrayOfReallyVeryLongStringNames[439] = "Hello world!";
var strRef = new ArrayStringReference(ArrayOfReallyVeryLongStringNames, 439);
Console.WriteLine(ArrayOfReallyVeryLongStringNames[439]); // Outputs "Hello world!"
strRef.Value = "Donkey Kong";
Console.WriteLine(ArrayOfReallyVeryLongStringNames[439]); // Outputs "Donkey Kong"
You could make this more convenient to use by providing an implicit string operator so you don't have to use .Value to access the underlying string:
// Add this to class ArrayStringReference implementation
public static implicit operator string(ArrayStringReference strRef)
{
return strRef.Value;
}
Then instead of having to access the underlying string like this:
strRef.Value = "Donkey Kong";
...
string someString = strRef.Value;
You can do this:
strRef.Value = "Donkey Kong";
...
string someString = strRef; // Don't need .Value
This is just syntactic sugar, but it might make it easier to start using an ArrayStringReference in existing code. (Note that you will still need to use .Value to set the underlying string.)
The closest you can get is this:
unsafe
{
string* a = &ArrayOfReallyVeryLongStringNames[439]; // no compile
}
Which gives an exception:
Cannot take the address of, get the size of, or declare a pointer to a managed type ('string')
So no, not possible...
Also read this MSDN article which explains what types can be used (blittable types).
When I do something like this in C#:
string a = "String 1";
string b = a;
a = "String 2";
Console.WriteLine(a); // String 2
Console.WriteLine(b); // String 1
The thing is, both "String 1" and "String 2" literals are created at the start of the program, and strings are always pointers: at first a references "String 1" literal and afterwards it references "String 2". If you want them to always reference the same thing, in C# you just use the same variable.
The string objects themselves are immutable in C#:
Because a string "modification" is actually a new string creation, you must use caution when you create references to strings. If you create a reference to a string, and then "modify" the original string, the reference will continue to point to the original object instead of the new object that was created when the string was modified.
When the string mutability is needed, for example, to concatenate a lot of strings faster, other classes are used, like StringBuilder.
To sum it up, what you're trying to do is impossible.
In C#, a String is an Object. Therefore String a = "Donkey Kong" says that a now have a reference to this string that is being allocated over the memory. Then all you need to do is:
ArrayOfReallyVeryLongStringNames[439] = a;
And that will copy the refrence (which you should be thinking of in C#!!!) to the location in the string.
BUT!! When you do a="new string";, a will get a new reference. See the example I made:
http://prntscr.com/3kw18v
You can only do this with unsafe mode.
You could create a wrapper
public class StringWrapper
{
public string Value {get;set;}
}
StringWrapper[] arrayOfWrappers = new StringWrapper[500];
arrayOfWrappers[439] = new StringWrapper { Value = "Hello World" };
StringWrapper a = arrayOfWrappers[439];
a.Value = "New Value";
What you are trying to do is universally discouraged, and actively prevented, in C#, where the logic should be independent of the memory model, however, refer to related SO question C# memory address and variable for some info.
EDIT 1
A more canonical approach to your actual problem in C# would be:
// using System.Linq;
string[] raw = new string[] { "alpha", "beta", "gamma", "delta" };
List<int> evenIndices = Enumerable.Range(0, raw.Length)
.Where(x => x % 2 == 0)
.ToList();
foreach (int x in evenIndices)
raw[x] = raw[x] + " (even)";
foreach (string x in raw)
Console.WriteLine(x);
/*
OUTPUT:
alpha (even)
beta
gamma (even)
delta
*/
If you really want to modify the original memory structure itself, then perhaps C++ is a more appropriate language choice for the solution.
EDIT 2
Looking around on SO, you may want to look at this answer Hidden Features of C#? to an unrelated question.
[TestMethod]
public void TestMethod1()
{
string[] arrayOfString = new string[500];
arrayOfString[499] = "Four Ninty Nine";
Console.WriteLine("Before Modification : {0} " , arrayOfString[499]);
string a = arrayOfString[499];
ModifyString(out arrayOfString[499]);
Console.WriteLine("after a : {0}", a);
Console.WriteLine("after arrayOfString [499]: {0}", arrayOfString[499]);
}
private void ModifyString(out string arrayItem)
{
arrayItem = "Five Hundred less one";
}
Of course you can, hehe:
var a = __makeref(array[666]);
__refvalue(a, string) = "hello";
But you would have to have a very good reason to do it this way.