Behavior of String in C# - c#

I am a C++ programmer, now working on a C# project.
I am trying to understand in the below snippet why the value of string does not change even though the function is changing its value, I thought it is an object and would be passed as a reference.
public class TestClass
{
public TestClass(String passedStr)
{
passedStr = "Change me";
}
}
class Program
{
static void Main(string[] args)
{
String aString="I am what i am";
TestClass obj = new TestClass(aString);
Console.WriteLine(aString);
}
}
But behavior with user defined classes are different.
public class TestClass
{
private int x;
public int ID
{
get
{
return x;
}
set
{
x = value;
}
}
public TestClass(int a)
{
x = a;
}
}
public class Tester
{
public Tester(TestClass obj)
{
obj.ID = 999;
}
}
class Program
{
static void Main(string[] args)
{
TestClass obj = new TestClass(555);
Tester tester = new Tester(obj);
Console.WriteLine(obj.ID);
}
}

Let's go back to basics.
A variable is a storage location.
A variable of type string is a storage location that stores either null, or a reference to a string.
"passedStr" and "aString" are different variables.
When you call "new TestClass(aString)" you create a new storage location for "passedStr" and copy the contents of "aString" into it. You now have two variables that have the same content: a reference to a string.
Inside the constructor you change the value stored in the storage location for "passedStr". "aString" remains the same.
The "ref" and "out" keywords in C# mean "make the formal parameter and the argument aliases of each other". In that case you have only one variable with two different names. When you change one of them the other one changes as well, because they are the same variable.

No, it's passed by value; there's no ref keyword.
It's passing a reference type (here, a class) by value (no ref keyword), just like passing a copy of a pointer in C++. You're reassigning the pointer, not the actual data (which you can't do with strings anyway).
If you need pass-by-reference, try:
public TestClass(ref String passedStr)
{
passedStr = "Change me";
}
...
TestClass obj = new TestClass(ref aString);

Strings are passed by reference but the pointer is passed by value in C#. If you want to pass the string by reference you'll have to make use of the ref key word.
For example:
public class TestClass
{
public TestClass(ref string passedStr)
{
passedStr = "Change me";
}
}
class Program
{
static void Main(string[] args)
{
string aString="I am what i am";
TestClass obj = new TestClass(ref aString);
Console.WriteLine(aString); // "Change me"
}
}

passedStr is not the string, but a constructor parameter that holds a reference to the string. All your TestClass constructor is doing is changing the string that this parameter references. It has no effect outside the constructor.

What you are doing in the constructor, is that you are assigning a new String literal to the local variable passedStr.
In C, the equivalent function would look something like this:
Testclass constructor_testclass(char* passedStr) {
passedStr = "Change me";
}
I think it's obvious that this function does not change the value of the char* in the calling function.

The object I am what i am is being passed by reference, but the reassignment is to a local variable. You don't change the original object, but instead assign a new object (Change me) to the location of the argument.

public class Employee
{
public string ID { get; set; }
public string Name { get; set; }
public override string ToString()
{
return string.Format("ID = {0} Name = {1}", ID, Name);
}
}
public class TestClass2
{
public TestClass2(Employee e)
{
e.ID="007";
e.Name="james";
}
}
static void Main()
{
Employee e = new Employee();
e.ID = "0";
e.Name = "nobody";
TestClass2 t = new TestClass2(e);
Console.WriteLine(e); //Output ID = 007 Name = James
}
strings are passed by reference but the pointer is passed by value in C#
Parameter passing in C# by Jon Skeet

Related

Error on static Class

public class Program
{
public static void Main(string[] args)
{
var c = check.myValue("Example 1"); //This is the pattern I've to use, don't want to create an object (Is it possible to use it with static class)
Console.WriteLine(c.result1);
Console.WriteLine(c.result2);
}
}
public static class check
{
public static void myValue(string qr)
{
public string result1 = "My Name" + qr;
public string result1 = "You're" + qr;
}
}
See here Online Example (Code is not working)
Every thing on main function I've to use exactly the same pattern because I'll use it in a lot of different classes and I don't want to create object each and every time by using non-static class.
Please correct me if I'm wrong
There's a lot wrong with the syntax of that code, which #Sergey addresses in his answer.
You appear to want to return an instance of a class from a static method, and that class should contain two properties.
You can do that by creating the actual, nonstatic class containing the properties:
public class Check
{
public string Result1 { get; set; }
public string Result2 { get; set; }
}
Then return a new instance from the static method therein:
public static Check MyValue(string qr)
{
var result = new Check();
result.Result1 = "My Name" + qr;
result.Result2 = "You're" + qr;
return result;
}
However, you're saying in the comments in your code that you don't want to use an object.
In that case it appears you want to use static properties. That's generally not recommendable, but it would look like this:
public static class Check
{
public static string Result1 { get; set; }
public static string Result2 { get; set; }
public static void MyValue(string qr)
{
Result1 = "My Name" + qr;
Result2 = "You're" + qr;
}
}
Then you can read Check.Result1 after calling the method MyValue().
Your code is totally wrong
myValue method returns void. You cannot assign void return value to variable.
You cannot have public modifiers for local variables.
You cannot have local variables with same name in same scope
If you want to return two values from method, then you should return object with two fields - custom class or tuple. You can also use out parameters, but I don't think it's your case
public static class Check
{
public static Tuple<string, string> MyValue(string qr)
{
return Tuple.Create($"My Name {qr}", $"You're {qr}");
}
}
With C# 7 it's a little bit better. You can write this method in one line and provide names for tuple properties
(string MyName, string YourName) MyValue(string qr) => ($"My Name {qr}", $"You're {qr}");
Usage
var result = Check.MyValue("Example 1");
Console.WriteLine(result.Item1); // result.MyName
Console.WriteLine(result.Item2); // result.YourName
You can practice with creating custom class with nicely named properties instead of using tuples.

.net variable value change on method call possible?

Greetings everyone
I was wondering if i have bool x = true; and i call a method after that might change x value. would this change apply if the method is void & don't return the result. Example :
bool x = true;
string x = "";
Change_value(x);
if (!(x))
x = "Ok";
would x value change when i call my method or do i need to do it as x = change_value(x)
This depends on the type of the variable you are passing to a method. In your example no.
Value types will not see changes reflected in the calling scope, where properties on reference values will.
This answer explains the concept well
Note that you can use the ref keyword to have value types updated like reference types also.
You can change members of reference values, but you cannot reassign
them.
namespace ConsoleApplication1
{
public class TestObj
{
public string Val { get; set; }
}
class Program
{
static void Main(string[] args)
{
var testObj = new TestObj { Val = "Initial instance" };
Console.WriteLine(testObj.Val);
AssignNewInstance(testObj);
Console.WriteLine(testObj.Val);
// Prints:
// 'Initial instance'
// 'Changed in AssignNewInstance'
// 'Initial instance'
}
public static void AssignNewInstance(TestObj testObj)
{
testObj = new TestObj { Val = "Changed in AssignNewInstance" };
Console.WriteLine(testObj.Val);
}
}
}`
I think what you might be looking for is passing a value type (bool) by reference. You can do this using the ref keyword. Here is the relevant excerpt:
The ref keyword causes an argument to be passed by reference, not by value. The effect of passing by reference is that any change to the parameter in the called method is reflected in the calling method.
So, it should change the variable if you change your code to this (add the "ref"):
bool x = true;
string x = "";
Change_value(ref x);
if (!(x))
x = "Ok";
And then the Change_value would be declared like this:
void Change_value(ref bool someBool) { //do whatever }
bool is a primitive, so it's passed by value (a copy passed to change_value).
If you want to change it's value in the method you can use the Boolean class, like that:
Boolean x = true;
string x = "";
Change_value(ref x);
if (!(x))
x = "Ok";
you have to use the ref prefix in the method parameters
void Change_value(ref Boolean x)
{
...
}
and call it like this:
Change_value(ref x);
you can go for MS explain: https://msdn.microsoft.com/en-us/library/14akc2c7.aspx
Unless you pass value X by reference the value of x should not change.
You can define b as a field inside your class. Once you did that, you just have to assign it and the new value will be available from that moment on.
Here is a short example:
public static class Program
{
private static bool b;
public static void Main()
{
b = true;
Console.WriteLine(b);
DoStuff();
Console.WriteLine(b);
}
private static void DoStuff()
{
b = false;
}
}
This way you can access and modify b from anywhere inside your class.

Is this the proper use of Action<T>

As I understand Func and Action; An Action does not return a value, and a Func does. In the below example I have a child class create an instance of "SomeContent" and pass a reference back to the parent class. My questions are:
Does this.ContentDelagate(content) pass by reference or by value?
In the below example, should I have used Func as I want a reference to an the instantiated SomeContent object? If so can you provide an example?
namespace DelegateTut
{
class Program
{
static void Main(string[] args)
{
TestClass myTest = new TestClass();
myTest.ContentDelagate += ContentDelegateHandler;
myTest.RunDel();
Console.Write("Press Enter to exit...\n");
Console.ReadLine();
}
public static void ContentDelegateHandler(SomeContent content) {
Console.WriteLine(content.ValueOne);
Console.WriteLine(content.ValueTwo);
}
}
}
public class TestClass {
public TestClass() { }
public Action<SomeContent> ContentDelagate { get; set; }
public void RunDel() {
SendContentToMainThread();
}
public void SendContentToMainThread() {
SomeContent content = new SomeContent {
ValueOne = "Hello",
ValueTwo = "World"
};
this.ContentDelagate(content);
}
}
public class SomeContent {
public String ValueOne { get; set; }
public String ValueTwo { get; set; }
public SomeContent() { }
}
Does this.ContentDelagate(content) pass by reference or by value?
This question is a little confusing. We are dealing with both a getter and a delegate as well. I think its clearer to show:
public void SendContentToMainThread()
{
SomeContent content = new SomeContent
{
ValueOne = "Hello",
ValueTwo = "World"
};
Action<SomeContent> myDel = ContentDelagate;//Property Get
myDel(content);//invoke delegate
Console.WriteLine(content.ValueOne);//refer to this below
}
The handler is called as part of the multicast delegate. The handler is being passed a class which is a reference type. In C# reference and value types are passed by value. The underlying value that is copied could be a value (value type) or a location in memory (reference type).
Because this is a reference type it has reference type behavior:
public static void ContentDelegateHandler(SomeContent content)
{
Console.WriteLine(content.ValueOne);
Console.WriteLine(content.ValueTwo);
content.ValueOne = "updated";
}
Now the modified code above Console.WriteLine(content.ValueOne); will print out the word "updated".
In the below example, should I have used Func as I want a reference to
an the instantiated SomeContent object? If so can you provide an
example?
There's nothing being returned in this case so no you should not use Func. Func does not have any impact whatsoever on your desire to have reference type behavior.

String class behavior

public void main()
{
string test = "testing";
ChangeVal(test);
Console.WriteLine(test);
}
private void ChangeVal(string test)
{
test = "in child";
}
If String is a class.
and i pass string as a parameter to a function. change the value of that string in function.
But in main function it shows the previous values. It will print testing value.
when i created Foo class which has 2 member variable integer and string.
when i passed the object of the class as parameter and change value of the member variable in function.
It will give updated value in the main function
public class Foo
{
public string test = "testing";
public int i = 5;
}
public void main()
{
Foo obj=new Foo();
Console.WriteLine(obj.test);
ChangeVal(obj);
Console.WriteLine(obj.test);
}
private void ChangeVal(Foo obj)
{
obj.test = "in child";
obj.i = 5;
}
If string is the class. It will update the value of the variable.
May string is the sequence of Unicode character that's why it doesn't update the value in 1st case.
Can any body will explain this in detail.
change the value of that string in function
Strings are immutable. You can't change the value of a string. You can assign another string to the same reference, but you would need to pass the reference in by using ref.
public void main()
{
string test = "testing";
ChangeVal(ref test);
Console.WriteLine(test);
}
private void ChangeVal(ref string test)
{
test = "in child";
}
You Foo class, however, is mutable, so you can assign different values to its members.
Try to pass the parameter by reference to get the var updated in main thread:
private void SeString(ref string chain)
{
chain="new string";
}
Then call:
string variable="hello";
SeString(ref variable);
string output is "new string"

How to share a variable between two classes?

How would you share the same object between two other objects? For instance, I'd like something in that flavor:
class A
{
private string foo_; // It could be any other class/struct too (Vector3, Matrix...)
public A (string shared)
{
this.foo_ = shared;
}
public void Bar()
{
this.foo_ = "changed";
}
}
...
// inside main
string str = "test";
A a = new A(str);
Console.WriteLine(str); // "test"
a.Bar();
Console.WriteLine(str); // I get "test" instead of "changed"... :(
Here, I don't want to give a ref to the Bar method. What I want to achieve is something that would look like that in C++:
class A
{
int* i;
public:
A(int* val);
};
A::A (int* val)
{
this->i = val;
}
I read there is some ref/out stuff, but I couldn't get what I'm asking here. I could only apply some changes in the methods scope where I was using ref/out arguments...
I also read we could use pointers, but is there no other way to do it?
This has nothing to do with sharing objects. You passed a reference to a string into the A constructor. That reference was copied into the private member foo_. Later, you called B(), which changed foo_ to "changed".
At no time did you modify str. str is a local variable in main. You never passed a reference to it.
If you had wanted to change str, you could have defined B as
public void Bar(ref string s)
{
this.foo_ = "changed";
s = this.foo_;
}
Consider:
public class C
{
public int Property {get;set;}
}
public class A
{
private C _c;
public A(C c){_c = c;}
public void ChangeC(int n) {_c.Property = n;}
}
public class B
{
private C _c;
public B(C c){_c = c;}
public void ChangeC(int n) {_c.Property = n;}
}
in main:
C myC = new C() {Property = 1;}
A myA = new A(myC);
B myB = new B(myC);
int i1 = myC.Property; // 1
myA.ChangeC(2);
int i2 = myC.Property; // 2
myB.ChangeC(3);
int i3 = myC.Property; // 3
Wrap your string inside a class. You need to do this because strings are immutable. Any attempt to change a string actually results in a new string.
class Foo {
class StringHolder {
public string Value { get; set; }
}
private StringHolder holder = new StringHolder();
public string Value {
get { return holder.Value; }
set { holder.Value = value; }
}
public Foo() { }
// this constructor creates a "linked" Foo
public Foo(Foo other) { this.holder = other.holder; }
}
// .. later ...
Foo a = new Foo { Value = "moose" };
Foo b = new Foo(a); // link b to a
b.Value = "elk";
// now a.Value also == "elk"
a.Value = "deer";
// now b.Value also == "deer"
I would split my answer to 2 parts:
1) If the variable is a reference type than it is already shared since you pass its reference to all interested objects. The only thing you should pay attention is that the reference type instances are mutable.
2) If the variable is a value type than you would have to use ref or out or some wrapper that is mutable and you can change the value inside the wrapper using a method or a property.
Hope that helps.
You need to pass the paramter as a reference to your method,
class A
{
private string foo_; // It could be any other class/struct too (Vector3, Matrix...)
public A(string shared)
{
this.foo_ = shared;
}
public void Bar(ref string myString)
{
myString = "changed";
}
}
static void Main()
{
string str = "test";
A a = new A(str);
Console.WriteLine(str); // "test"
a.Bar(ref str);
Console.WriteLine(str);
}
When a variable is a string, it is a reference.
Try to clone the string. http://msdn.microsoft.com/en-us/library/system.string.clone.aspx

Categories

Resources