This below code compiles and works out as intended.
class MyClass1
{
public void test()
{
string one = "testString1";
Console.WriteLine("MyClass1: " + one);
new MyClass2().test(one);
Console.WriteLine(one); //again testString1 is printed.
}
}
class MyClass2
{
public void test(string two)
{
Console.WriteLine("Test method");
Console.WriteLine(two);
two = "pilot";
Console.WriteLine(two);
}
}
all I infer from this is:
The value assigned to the string in test method is local to that function and the changes will be reflected only if I use a ref or out.
The question is:
We all know that the string is a reference type (because it is of type, String)
So, for all the reference types : when passing around their objects, the changes should be reflected right ? (For ex, for the same example, if I pass around a object of a class, then any changes are reflected back right ?)
Why is this rule not followed here ?
Can any one point me in understanding what happens under the hood ?
Although strings are reference objects, they are also immutable. Since references are passed by value *, changes to variables representing the reference, are not reflected on the original.
To demonstrate the effect of passing reference objects, replace string with StringBuilder, and change the content inside the test method:
class MyClass1
{
public void test()
{
StringBuilder one = new StringBuilder("testString1");
Console.WriteLine("MyClass1: " + one);
new MyClass2().test(one);
Console.WriteLine(one); //testString1pilot is printed.
}
}
class MyClass2
{
public void test(StringBuilder two)
{
Console.WriteLine("Test method");
Console.WriteLine(two);
two.Append("pilot");
Console.WriteLine(two);
}
}
* Unless the method specifies a different mode of parameter passing, e.g. out or ref.
So, for all the reference types : when passing around their objects,
the changes should be reflected right ?
All reference types are passed by reference is not true.
all reference type or value types are passed by value by default.
if you want to pass any type as reference types you need to use ref or out keyword.
Note: String is a immutable type means Strings can not be changed.
That is the reason why you are not able to see the changes made in the called function.
You need to use StringBuilder to get back the changes.
JonSteek has explained about Parmeter passing well here
In your example, the fact that String is a reference type does not matter. The exact same thing would happen with any value type or even a mutable reference type (like a class).
This is because the parameter to a method normally acts like a local variable within the method. Changes made to the parameter are local to the method.
As you stated, the exception is when the parameter is ref or out.
You have to understand the difference between the string which is a reference type and the variable itself that points to that object.
two = "pilot";
When you do this, you are creating a new string object and telling variable two to now point to this new string. The variable one still points to the original string, which is a different object.
Related
I am reading following blog by Eric Lippert: The truth about Value types
In this, he mentions there are 3 kinds of values in the opening:
Instance of Value types
Instance of Reference types
References
It is incomplete. What about references? References are neither value types nor instances of reference types, but they are values..
So, in the following example:
int i = 10;
string s = "Hello"
First is instance of value type and second is instance of reference type. So, what is the third type, References and how do we obtain that?
So, what is the third type, References and how do we obtain that?
The variable s is a variable which holds the value of the reference. This value is a reference to a string (with a value of "Hello") in memory.
To make this more clear, say you have:
string s1 = "Hello";
string s2 = s1;
In this case, s1 and s2 are both variables that are each a reference to the same reference type instance (the string). There is only a single actual string instance (the reference type) involved here, but there are two references to that instance.
Fields and variables of reference type, such as your s, are references to an instance of a reference type that lives on the heap.
You never use an instance of a reference type directly; instead, you use it through a reference.
A reference is not really a 'third type'. It's actually a pointer that refers to a concrete instance of an object. Take a look at this example:
class MyClass
{
public string Str { get; set; }
}
class Program
{
static void Main(string[] args)
{
int a = 1;
int b = 2;
int c = 3;
var myObj = new MyClass
{
Str = "Whatever"
};
Console.WriteLine("{0};\t{1};\t{2};\t{3}", a, b, c, myObj.Str);
MyFunction(a, ref b, out c, myObj);
Console.WriteLine("{0};\t{1};\t{2};\t{3}", a, b, c, myObj.Str);
Console.ReadLine();
}
static void MyFunction(int justValue, ref int refInt, out int outInt, MyClass obj)
{
obj.Str = "Hello";
justValue = 101;
refInt = 102;
outInt = 103; // similar to refInt, but you MUST set the value of the parameter if it's uses 'out' keyword
}
}
The output of this program is:
1; 2; 3; Whatever
1; 102; 103; Hello
Focus on the MyFunction:
The first parameter we pass is a simple int which is a value type. By default value types are cloned when passed as the parameter (a new instance is being created). That's why the value of 'a' didn't change.
You can change this behavior by adding 'ref' or 'out' keyword to the parameter. In this case you actually pass a reference to that very instance of your int. In MyFunction the value of that instance is being overridden.
Here you can read move out ref and out
The last example is the object of MyClass. All classes are reference types and that's why you always pass them as references (no special keywords needed).
You can think about a reference as about an address in computer memory. Bytes at that address compose your object. If you pass it as value, you take that bytes out and pass them to a function. If you pass it as a reference you only pass the address. Than in your called function you can read bytes from that address or write to that address. Every change affects the calling function variables, because they point to exactly the same bytes in computer memory. It's not exactly what happens in .Net (it runs in a virtual machine), but I think this analogy will help you understand the concept.
Why do we use references? There are many reasons. One of them is that passing a big object by value would be very slow and would require cloning it. When you pass a reference to an object, than no matter how big that object is you only pass w few bytes that contain it's 'address' in memory.
Moreover your object may contain elements that cannot be cloned (like an open socket). Using reference you can easily pass such an object between functions.
It's also worth mentioning that sctructs, even though they look very similar to classes are actually value types and behave as value types (when you pass a struct to a function, you actually pass a clone - a new instance).
I always thought that a method parameter with a class type is passed as a reference parameter by default. Apparently that is not always the case. Consider these unit tests in C# (using MSTest).
[TestClass]
public class Sandbox
{
private class TestRefClass
{
public int TestInt { get; set; }
}
private void TestDefaultMethod(TestRefClass testClass)
{
testClass.TestInt = 1;
}
private void TestAssignmentMethod(TestRefClass testClass)
{
testClass = new TestRefClass() { TestInt = 1 };
}
private void TestAssignmentRefMethod(ref TestRefClass testClass)
{
testClass = new TestRefClass() { TestInt = 1 };
}
[TestMethod]
public void DefaultTest()
{
var testObj = new TestRefClass() { TestInt = 0 };
TestDefaultMethod(testObj);
Assert.IsTrue(testObj.TestInt == 1);
}
[TestMethod]
public void AssignmentTest()
{
var testObj = new TestRefClass() { TestInt = 0 };
TestAssignmentMethod(testObj);
Assert.IsTrue(testObj.TestInt == 1);
}
[TestMethod]
public void AssignmentRefTest()
{
var testObj = new TestRefClass() { TestInt = 0 };
TestAssignmentRefMethod(ref testObj);
Assert.IsTrue(testObj.TestInt == 1);
}
}
The results are that AssignmentTest() fails and the other two test methods pass. I assume the issue is that assigning a new instance to the testClass parameter breaks the parameter reference, but somehow explicitly adding the ref keyword fixes this.
Can anyone give a good, detailed explanation of whats going on here? I'm mainly just trying to expand my knowledge of C#; I don't have any specific scenario I'm trying to solve...
The thing that is nearly always forgotten is that a class isn't passed by reference, the reference to the class is passed by value.
This is important. Instead of copying the entire class (pass by value in the stereotypical sense), the reference to that class (I'm trying to avoid saying "pointer") is copied. This is 4 or 8 bytes; much more palatable than copying the whole class and in effect means the class is passed "by reference".
At this point, the method has it's own copy of the reference to the class. Assignment to that reference is scoped within the method (the method re-assigned only its own copy of the reference).
Dereferencing that reference (as in, talking to class members) would work as you'd expect: you'd see the underlying class unless you change it to look at a new instance (which is what you do in your failing test).
Using the ref keyword is effectively passing the reference itself by reference (pointer to a pointer sort of thing).
As always, Jon Skeet has provided a very well written overview:
http://www.yoda.arachsys.com/csharp/parameters.html
Pay attention to the "Reference parameters" part:
Reference parameters don't pass the values of the variables used in
the function member invocation - they use the variables themselves.
If the method assigns something to a ref reference, then the caller's copy is also affected (as you have observed) because they are looking at the same reference to an instance in memory (as opposed to each having their own copy).
The default convention for parameters in C# is pass by value. This is true whether the parameter is a class or struct. In the class case just the reference is passed by value while in the struct case a shallow copy of the entire object is passed.
When you enter the TestAssignmentMethod there are 2 references to a single object: testObj which lives in AssignmentTest and testClass which lives in TestAssignmentMethod. If you were to mutate the actual object via testClass or testObj it would be visible to both references since they both point to the same object. In the first line though you execute
testClass = new TestRefClass() { TestInt = 1 }
This creates a new object and points testClass to it. This doesn't alter where the testObj reference points in any way because testClass is an independent copy. There are now 2 objects and 2 references which each reference pointing to a different object instance.
If you want pass by reference semantics you need to use a ref parameter.
My 2 cents
When a class is passed to a method, a copy of its memory space address is being sent (a direction to your house is being sent). So any operation on that address will affect the house but will not change the address itself. (This is default).
Passing a class (object) by reference has an effect of passing its actual address instead of a copy of an address. That means if you assign a new object to an argument passed by reference it will change the actual address (similar to relocation). :D
This is how I see it.
The AssignmentTest uses TestAssignmentMethod which only changes the object reference passed by value.
So the object itself is passed by reference but the reference to the object is passed by value. so when you do:
testClass = new TestRefClass() { TestInt = 1 };
You are changing the local copied reference passed to the method not the reference you have in the test.
So here:
[TestMethod]
public void AssignmentTest()
{
var testObj = new TestRefClass() { TestInt = 0 };
TestAssignmentMethod(testObj);
Assert.IsTrue(testObj.TestInt == 1);
}
testObj is a reference variable. When you pass it to TestAssignmentMethod(testObj);, the refernce is passed by value. so when you change it in the method, original reference still points to the same object.
There are lot's of subtleties missed in the posted answers here that will create unexpected results and confuse new C# developers. There are actually two ways to process a reference passed by value in C# methods.
All methods in C# pass arguments in BY VALUE by default unless you use the ref, in, or out keywords. Passing a REFERENCE BY VALUE means a COPY of the MEMORY ADDRESS of the object used by the outside reference is passed in and assigned to the method parameter. The original outside variable address is not passed in nor the original object in memory, just the memory address to the object.
Both variables now point to the same object in memory.
This copy of the address to the object in memory is the VALUE for pass by value for all reference types. That means the original reference variable that points to the object address remains the same, and a new copy of that memory address is assigned to a new variable in the method parameter. They BOTH point to the same object. That means if either change properties on the object, it will affect the original object and will be seen by both variables.
This seems to act like a PASS BY REFERENCE, but it is not. That is what confuses many developers.
But this means some "weird" and unexpected things can happen passing a reference by value in methods if you are not careful. It means your method variable can connect to the same object and change the properties and fields of the original shared object ...BUT... as soon as you reassign the method variable to a new instance of the same type of object, it loses a connection to the original instance and no longer affects the original object used by the outside reference.
You might assume the method has assigned a fresh object to the outside reference variable, but you have not! Changing that new object's properties in the method no longer affect the outside reference. So BE CAREFUL!
Let's test this weirdness in C#:
// First, create my cat class. I can change its name
// to anything I want. But instead, I want it to have
// a special name assigned by the next class via a method.
class MyCat
{
public string Name { get; set; }
}
// This special class will assign a popular name to me cat.
class CatNames
{
public enum PopularNames {
Felix,
Fluffy
}
public void ChangeName(MyCat c)
{
PopularNames p = PopularNames.Felix;
c.Name = p.ToString();
}
public void ChangeNameAndCat(MyCat c)
{
PopularNames p = PopularNames.Fluffy;
MyCat d = new MyCat();
d.Name = p.ToString();
c = d;
// Note: In this case, you might want to return the new "MyCat"
// object and its name to the caller.
}
}
// Testing passing by value and how references are passed...
CatNames catnamechanger = new CatNames();
// I created two cats with the same name so you can see
// what names actually changed below.
MyCat cat1 = new MyCat();
cat1.Name = "Bubba";
MyCat cat2 = new MyCat();
cat2.Name = "Bubba";
catnamechanger.ChangeName(cat1);
catnamechanger.ChangeNameAndCat(cat2);
Console.WriteLine("My Cat1's Name is: " + cat1.Name);
Console.WriteLine("My Cat2's Name is: " + cat2.Name);
// ============== OUTPUT ==================
// My Cat1's Name is: Felix
// My Cat2's Name is: Bubba <<< OOPS! My cat name kept the original
RESULTS
Notice the first cat had its name changed on the original object, but the second cat kept its original name, "Bubba", as a new cat was assigned to the method variable. It lost connection to the original object. The reason is, passing a reference by value still allows you to affect properties of the passed in address to the original object. But as soon as you change where the method variable points, that reference is lost.
Can you please tell me what is the exact use of out parameter?
Related Question:
What is the difference between ref and out? (C#)
The best example of a good use of an out parameter are in the TryParse methods.
int result =-1;
if (!Int32.TryParse(SomeString, out result){
// log bad input
}
return result;
Using TryParse instead of ParseInt removes the need to handle exceptions and makes the code much more elegant.
The out parameter essentially allows for more than one return values from a method.
The out method parameter keyword on a
method parameter causes a method to
refer to the same variable that was
passed into the method. Any changes
made to the parameter in the method
will be reflected in that variable
when control passes back to the
calling method.
Declaring an out method is useful when
you want a method to return multiple
values. A method that uses an out
parameter can still return a value. A
method can have more than one out
parameter.
To use an out parameter, the argument
must explicitly be passed to the
method as an out argument. The value
of an out argument will not be passed
to the out parameter.
A variable passed as an out argument
need not be initialized. However, the
out parameter must be assigned a value
before the method returns.
An Example:
using System;
public class MyClass
{
public static int TestOut(out char i)
{
i = 'b';
return -1;
}
public static void Main()
{
char i; // variable need not be initialized
Console.WriteLine(TestOut(out i));
Console.WriteLine(i);
}
}
http://msdn.microsoft.com/en-us/vcsharp/aa336814.aspx
Out parameters are output only parameters meaning they can only passback a value from a function.We create a "out" parameter by preceding the parameter data type with the out modifier. When ever a "out" parameter is passed only an unassigned reference is passed to the function.
using System;
class ParameterTest
{
static void Mymethod(out int Param1)
{
Param1=100;
}
static void Main()
{
int Myvalue=5;
MyMethod(Myvalue);
Console.WriteLine(out Myvalue);
}
}
Output of the above program would be 100 since the value of the "out" parameter is passed back to the calling part. Note
The modifier "out" should precede the parameter being passed even in the calling part. "out" parameters cannot be used within the function before assigning a value to it. A value should be assigned to the "out" parameter before the method returns.
Besides allowing you to have multiple return values, another use is to reduce overhead when copying a large value type to a method. When you pass something to a method, a copy of the value of that something is made. If it's a reference type (string for example) then a copy of the reference (the value of a reference type) is made. However, when you copy a value type (a struct like int or double) a copy of the entire thing is made (the value of a value type is the thing itself). Now, a reference is 4 bytes (on 32-bit applications) and an int is 4 bytes, so the copying is not a problem. However, it's possible to have very large value types and while that's not recommended, it might be needed sometimes. And when you have a value type of say, 64 bytes, the cost of copying it to methods is prohibitive (especially when you use such a large struct for performance reasons in the first place). When you use out, no copy of the object is made, you simply refer to the same thing.
public struct BigStruct
{
public int A, B, C, D, E, F, G, H, J, J, K, L, M, N, O, P;
}
SomeMethod(instanceOfBigStruct); // A copy is made of this 64-byte struct.
SomeOtherMethod(out instanceOfBigStruct); // No copy is made
A second use directly in line with this is that, because you don't make a copy of the struct, but refer to the same thing in the method as you do outside of the method, any changes made to the object inside the method, are persisted outside the method. This is already the case in a reference type, but not in value types.
Some examples:
public void ReferenceExample(SomeReferenceType s)
{
s.SomeProperty = "a string"; // The change is persisted to outside of the method
}
public void ValueTypeExample(BigStruct b)
{
b.A = 5; // Has no effect on the original BigStruct that you passed into the method, because b is a copy!
}
public void ValueTypeExampleOut(out BigStruct b)
{
b = new BigStruct();
b.A = 5; // Works, because you refer to the same thing here
}
Now, you may have noticed that inside ValueTypeExampleOut I made a new instance of BigStruct. That is because, if you use out, you must assign the variable to something before you exit the method.
There is however, another keyword, ref which is identical except that you are not forced to assign it within the method. However, that also means you can't pass in an unassigned variable, which would make that nice Try.. pattern not compile when used with ref.
int a;
if(TrySomething(out a)) {}
That works because TrySomething is forced to assign something to a.
int a;
if(TrySomething(ref a)) {}
This won't work because a is unassigned (just declared) and ref requires that you only use it with an assigned variable.
This works because a is assigned:
int a = 0;
if(TrySomething(ref a)) {}
However, in both cases (ref and out) any changes made to a within the TrySomething method are persisted to a.
As I already said, changes made to a reference type are persisted outside the method in which you make them, because through the reference, you refer to the same thing.
However, this doesn't do anything:
public void Example(SomeReferenceType s)
{
s = null;
}
Here, you just set the copy of a reference to s to null, which only exists within the scope of the method. It has zero effect on whatever you passed into the method.
If you want to do this, for whatever reason, use this:
public void Example1(ref SomeReferenceType s)
{
s = null; // Sets whatever you passed into the method to null
}
I think this covers all use-cases of out and ref.
from http://msdn.microsoft.com/en-us/vcsharp/aa336814.aspx
One way to think of out parameters is that they are like additional return values of a method. They are very convenient when a method returns more than one value, in this example firstName and lastName. Out parameters can be abused however. As a matter of good programming style if you find yourself writing a method with many out parameters then you should think about refactoring your code. One possible solution is to package all the return values into a single struct.
In contrast ref parameters are considered initially assigned by the callee. As such, the callee is not required to assign to the ref parameter before use. Ref parameters are passed both into and out of a method.
The typical use case is a method that needs to return more than one thing, so it can't just use the return value. Commonly, the return value is used for a success flag while the out parameter(s) sets values when the method is successful.
The classic example is:
public bool TryGet(
string key,
out string value
)
If it returns true, then value is set. Otherwise, it's not. This lets you write code such as:
string value;
if (!lookupDictionary.TryGet("some key", out value))
value = "default";
Note that this doesn't require you to call Contains before using an indexer, which makes it faster and cleaner. I should also add that, unlike the very similar ref modifier, the compiler won't complain if the out parameter was never initialized.
In simple words pass any variable to the function by reference so that any changes made to that variable in side that function will be persistent when function returns from execution.
Jon Skeet describes the different ways of passing parameters in great detail in this article. In short, an out parameter is a parameter that is passed uninitialized to a method. That method is then required to initialize the parameter before any possible return.
generally we cannot get the variables inside a function if we don't get by a return value.
but use keyword "out" we can change it value by a function.
In c# , when sending a parameter to a method, when should we use "ref" and when "out" and when without any of them?
In general, you should avoid using ref and out, if possible.
That being said, use ref when the method might need to modify the value. Use out when the method always should assign something to the value.
The difference between ref and out, is that when using out, the compiler enforces the rule, that you need to assign something to the out paramter before returning. When using ref, you must assign a value to the variable before using it as a ref parameter.
Obviously, the above applies, when you are writing your own methods. If you need to call methods that was declared with the ref or out modifiers on their parameters, you should use the same modifier before your parameter, when calling the method.
Also remember, that C# passes reference types (classes) by reference (as in, the reference is passed by value). So if you provide some method with a reference type as a parameter, the method can modify the data of the object; even without ref or out. But it cannot modify the reference itself (as in, it cannot modify which object is being referenced).
They are used mainly to obtain multiple return values from a method call. Personally, I tend to not use them. If I want multiple return values from a method then I'll create a small class to hold them.
ref and out are used when you want something back from the method in that parameter. As I recall, they both actually compile down to the same IL, but C# puts in place some extra stuff so you have to be specific.
Here are some examples:
static void Main(string[] args)
{
string myString;
MyMethod0(myString);
Console.WriteLine(myString);
Console.ReadLine();
}
public static void MyMethod0(string param1)
{
param1 = "Hello";
}
The above won't compile because myString is never initialised. If myString is initialised to string.Empty then the output of the program will be a empty line because all MyMethod0 does is assign a new string to a local reference to param1.
static void Main(string[] args)
{
string myString;
MyMethod1(out myString);
Console.WriteLine(myString);
Console.ReadLine();
}
public static void MyMethod1(out string param1)
{
param1 = "Hello";
}
myString is not initialised in the Main method, yet, the program outputs "Hello". This is because the myString reference in the Main method is being updated from MyMethod1. MyMethod1 does not expect param1 to already contain anything, so it can be left uninitialised. However, the method should be assigning something.
static void Main(string[] args)
{
string myString;
MyMethod2(ref myString);
Console.WriteLine(myString);
Console.ReadLine();
}
public static void MyMethod2(ref string param1)
{
param1 = "Hello";
}
This, again, will not compile. This is because ref demands that myString in the Main method is initialised to something first. But, if the Main method is changed so that myString is initialised to string.Empty then the code will compile and the output will be Hello.
So, the difference is out can be used with an uninitialised object, ref must be passed an initialised object. And if you pass an object without either the reference to it cannot be replaced.
Just to be clear: If the object being passed is a reference type already then the method can update the object and the updates are reflected in the calling code, however the reference to the object cannot be changed. So if I write code like this:
static void Main(string[] args)
{
string myString = "Hello";
MyMethod0(myString);
Console.WriteLine(myString);
Console.ReadLine();
}
public static void MyMethod0(string param1)
{
param1 = "World";
}
The output from the program will be Hello, and not World because the method only changed its local copy of the reference, not the reference that was passed in.
I hope this makes sense. My general rule of thumb is simply not to use them. I feel it is a throw back to pre-OO days. (But, that's just my opinion)
(this is supplemental to the existing answers - a few extra considerations)
There is another scenario for using ref with C#, more commonly seen in things like XNA... Normally, when you pass a value-type (struct) around, it gets cloned. This uses stack-space and a few CPU cycles, and has the side-effect that any modifications to the struct in the invoked method are lost.
(aside: normally structs should be immutable, but mutable structs isn't uncommon in XNA)
To get around this, it is quite common to see ref in such programs.
But in most programs (i.e. where you are using classes as the default), you can normally just pass the reference "by value" (i.e. no ref/out).
Another very common use-case of out is the Try* pattern, for example:
string s = Console.ReadLine();
int i;
if(int.TryParse(s, out i)) {
Console.WriteLine("You entered a valid int: " + i);
}
Or similarly, TryGetValue on a dictionary.
This could use a tuple instead, but it is such a common pattern that it is reasonably understood, even by people who struggle with too much ref/out.
Very simple really. You use exactly the same keyword that the parameter was originally declared with in the method. If it was declared as out, you have to use out. If it was declared as ref, you have to use ref.
In addition to Colin's detailed answer, you could also use out parameters to return multiple values from one method call. See for example the method below which returns 3 values.
static void AssignSomeValues(out int first, out bool second, out string third)
{
first = 12 + 12;
second = false;
third = "Output parameters are okay";
}
You could use it like so
static void Main(string[] args) {
int i;
string s;
bool b;
AssignSomeValues(out i, out b, out s);
Console.WriteLine("Int value: {0}", i);
Console.WriteLine("Bool value: {0}", b);
Console.WriteLine("String value: {0}", s);
//wait for enter key to terminate program
Console.ReadLine(); }
Just make sure that you assign a valid value to each out parameter to avoid getting an error.
Try to avoid using ref. Out is okay, because you know what will happen, the old value will be gone and a new value will be in your variable even if the function failed. However, just by looking at the function you have no idea what will happen to a ref parameter. It may be the same, modified, or an entirely new object.
Whenever I see ref, I get nervous.
ref is to be avoided (I beleive there is an fx-cop rule for this also) however use ref when the object that is reference may itself changed. If you see the 'ref' keyword you know that the underlying object may no longer be referenced by the same variable after the method is called.
I have one doubt in string .
How can we acess the memory of string?
is String is reference type or Value type?
1) if it is Reference type then do the following code
List<String> strLst = new List<string>() { "abc","def","12"};
strLst.ForEach(delegate(string s)
{
if (s == "12")
{
s = "wser";
// I doubted whether = operator is overloaded in string class
//StringBuilder sb = new StringBuilder(s);
//s = sb.Append("eiru").ToString();
s = String.Concat(s, "sdf");
}
});
See that value of string is not changed. My question is why the string value is not changed?
If it is reference type then the string value should be changed.
class emp
{
public string id;
}
List<emp> e = new List<emp>() { new emp() { id = "sdf" }, new emp() { id = "1" }, new emp() { id = "2" } };
e.ForEach(delegate(emp em)
{
if (em.id == "1")
em.id = "fghe";
});
Here value is changed because emp is reference type
2) if string is value type
public sealed class String : IComparable, ICloneable, IConvertible, IComparable<string>, IEnumerable<char>, IEnumerable, IEquatable<string>
then why do they mentione that string is a class?
This is happening because of this part:
s = "wser";
This is exactly equivalent to:
s = new String ("wser");
When you write this, a new object is instantiated and its reference is stored in s. Thus, the previous reference is completely lost in the function scope and no change is noticed outside the scope.
Thus, to notice changes in a reference type changed in another scope, you cannot create a new instance and assign it to the variable name, you must modify the original reference itself (and this is not possible for a string object in Java - strings are immutable).
The System.String type is indeed a reference type, albeit a rather strange one. It is immutable from a developer's perspective, and the CLR treats it pretty much like a value type, so you won't go far wrong doing the same.
Jon Skeet's article on parameter passing, value types, and reference types in C#, also gives a good explanation of this curiosity:
Note that many types (such as string)
appear in some ways to be value types,
but in fact are reference types. These
are known as immutable types. This
means that once an instance has been
constructed, it can't be changed. This
allows a reference type to act
similarly to a value type in some ways
- in particular, if you hold a reference to an immutable object, you
can feel comfortable in returning it
from a method or passing it to another
method, safe in the knowledge that it
won't be changed behind your back.
This is why, for instance, the
string.Replace doesn't change the
string it is called on, but returns a
new instance with the new string data
in - if the original string were
changed, any other variables holding a
reference to the string would see the
change, which is very rarely what is
desired.
If you store the reference to an object in a variable and then change the reference, the object does not change, only the variable. You're changing a propert of em, thus affecting the object references by the variable em. If you instead did em = something, it would behave like the String example and not affect anything either.
The String type is a reference type, but it is immutable. This means you can't change the contents of the string.
It actually behaves like a value type, but only references are passed around, instead of the whole string object.
From the MSDN online page - string
Strings are immutable--the contents of a string object cannot be changed. Although string is a reference type, the equality operators (== and !=) are defined to compare the values of string objects, not references.
Why can't strings be mutable in Java and .NET?
String is a reference type.
The reason why the string in the list is not changing in your example, is that the method doesn't get access to the item in the list, it only gets a copy of the reference. The argument s is just a local variable in the method, so assigning a new value to it doesn't affect the contents of the list.