Possible this question seems duplicate but I explored stackoverflow article but noone gives answer to question.
I am trying to understand string data type behave. As we know string is immutable and reference data type.
So when we are passing a reference type parameter and change value in calling method , we get changes intact in caller method like as below code. e.g. we have user object which is passing as argument to a method "show" and this method change the value of user object and we get updated value in main method.This is happening as user is reference type.
When we passed string data type which is also reference type and immutable to print method and change value , we do not get updated value of string variable in main method.
Why this is behaving different than user object.?
When we passed string with ref parameter , we get updated value in main method. Here it is behaving like pass by ref.
So, string behaves like pass by value by default but this is pass by reference indeed, Why?
public class test
{
public void Show(User user)
{
user.id = 2;
user.Name = "Change";
}
public void Print(string test)
{
test = "new name";
}
}
public class User
{
public int id { get; set; }
public string Name { get; set; }
}
Main method
User user = new User { id = 1, Name = "New" };
test test = new test();
test.Show(user);
string name = "old name";
test.Print(name);
I read c-sharp-string this and most reply is stating that two variables are pointing to same location. so if it is, then change to one value should reflect in both places.
Under the hood objects are just pointers so when you pass in an object as an argument you are essentially copying the address of the instance into the function. So when you change the parameters of the passed object you are changing the parameters of the original instance. Now if you want to edit an int that is being passed as an argument you need to use the ref keyword. Also it might be interesting how this:
public void Show(User user)
{
user.id = 2;
user.Name = "Change";
user = null;
}
Will change the parameters of the object but the user object won't be set to null. That is because we are only changing our local pointer to the instance in memory instead of actually changing the pointer we passed. But if we passed this using the ref keyword this would set the original instance we had in main to null.
I may think string is called reference type. Because in C# when there are two string with same values or you have two strings and copy the value of one string to another. I will logically be not copied, until unless you change the value of second string. The second string will point to the same location as the first one. And in the above program you passed string as a value (am i write in this? no keyword ref is used, string is by default reference type, but if it is passed in parameter like this, and value change in original string then how can you be able to avoid reference of string while passing it in the parameter. (String is logically called reference typed : recommending a book, Read in that with detail will give you more knowledge about string data type in strings chapter.)
Related
I have a observed a strange behavior today in my application. I have one the methods as follows in my Data Access layer:
public async Task<Order> WriteOrder(Order orderDetails)
{
try
{
Order updatedOrder = GenerateOrderID(orderDetails);
Task insertOrder = orderCollection.InsertOneAsync(orderDetails); // updatedOrder was supposed to be passed here.
// inserts values into Database.
}
}
private Order GenerateOrderID(Order order)
{
try
{
order.Id = Guid.NewGuid().ToString();
order.SubmittedOn = DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss");
return order;
}
catch(Exception ex)
{
throw;
}
}
public class Order
{
[DataMember(Name = "id")]
public string Id { get; set; }
[DataMember(Name = "submittedOn")]
public string SubmittedOn { get; set; }
// some other Data Memebers
}
Explaination :
WriteOrder method is receiving orderDetails as input parameter, then I'm passing this to GeneratedOrderId method , where Id and few other details are updated and the order object is returned. We are receiving the object in updatedOrder object(which we are not using anywhere). Then orderdetails object is passed to InsertOneAsync method and is inserted in database.
All this time I haven't noticed it , but I was supposed to pass updatedOrder as the parameter to InsertOneAsync method, instead of orderDetails.
But somehow it was working, i.e Id and SubmittedOn details as getting updated in the database.When I debugged and saw , orderDetails object is also getting updated (which according to me is not supposed to). Why and how is this happening?
The basic thing to understand here is the when we pass an object of reference type to a method, the reference is passed by value. In your code there is no where a new object of Order has been created.
So what happens is that the state of same object is being updated wherever you are changing the values of properties. There is just single object in memory and you have different copies which point to the same reference.
Which means that in following method call:
private Order GenerateOrderID(Order order)
the order variable is holding the same object which is pointed by orderDetails at caller end. Two copies of reference but pointing to same object in memory.
A small change in your method will completely change the behaviour, if you create new object of Order in the private method. then you will see that the passed object does not gets updated. See:
private Order GenerateOrderID(Order order)
{
try
{
order = new Order(); // note this line
order.Id = Guid.NewGuid().ToString();
order.SubmittedOn = DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss");
return order;
}
catch(Exception ex)
{
throw;
}
}
Now we have a new object out there which we set it's state. Now the updatedOrder and orderDetails both are reference to different objects and changing state of one will not result is changing the other.
Note that this applies to reference types in c# i.e. classes and interfaces objects, not to value types lile int , long, struct etc
From learn.microsoft.com:
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 belonging to the
referenced object, such as the value of a class member.
You are passing a reference to orderDetails object to GenerateOrderID method. So the object that you are modifying in this method is still the same object. GenerateOrderID execution changes the state of this object. So when you are passing orderDetails to InsertOneAsync method, the reference you are passing references changed object that you were modifying in GenerateOrderID.
I guess you were thinking that when you pass the orderDetails, you were passing a copy of the object - but it is not true. You are passing the copy of the reference. So if you would assign something to the order reference inside of the method, the orderDetails in WriteOrder method reference would still reference the old object. But here you are changing some fields of the object that you are pointing to.
I recommend reading this.
I have a class that uses another class.
The first class have this method:
public void myMethod()
{
//Parameters are an enumeration.
// Really is a exchange variable between this class
//and the other class.
Paramters myParameter = Parameters.Option1;
MyClass2 myOtherClass = new MyClass2(myParameter);
}
The second class:
public enum Parameters { Option1, Option2, Option3 }
MyClass2
{
Parameters _myParameters;
Public MyClass2(Parameters paramParameters)
{
_myParameters = paramParameters;
}
private void clickButton()
{
_myParameters = Parameters.Option2;
this.Dispose();
}
}
What I what it is create a dialog and Parameters are an enumeration that is to serve as exchange between the main window and the dialog to notify about the selection in the dialog.
However, when in the clickButton I change the value of the _myParameters, it is not changed in the object that was passed as parameter in the constructor of MyClass2.
If instead of using an enumeration as exchange variable I create a class that has the enumeration, then I can get the selection. The exchange class would be like this:
class MyExchangeClass
{
Parameters myOption;
}
Then the code would be:
public void myMethod()
{
//Parameters are an enumeration.
// Really is a exchange variable between this class
//and the other class.
MyExchangeClass mySelection= new MyExchangeClass();
MyClass2 myOtherClass = new MyClass2(mySelection);
}
The second class:
public MyExchangeClass
{
Parameters enum MySelection { Option1, Option2, Option3 }
}
class MyClass2
{
MyExchangeClass _mySelection;
Public MyClass2(MyExchangeClassparamParameters)
{
_mySelection= paramParameters;
}
private void clickButton()
{
_mySelection.MySelection = Parameters.Option2;
this.Dispose();
}
}
In this way, the Class1, the main window, gets the updated value in the property of the class MyExchangeClass.
I would like to know why in the first solution the enumeration is not updated, because if it would possible, I would like to avoid the needed to wrap the enumeration in a class.
However, when in the clickButton I change the value of the _myParameters, is not changed in the object that was passed as parameter in the constructor of MyClass2.
No, it wouldn't be. The value was passed in by value - the two variables (myParameter and _myParameters) are independent variables. A change to one variable does not affect the other variable. This is how all types work in C#.
For changes to a parameter within a method to be seen by the caller, you could use a ref parameter, but that's not viable in your case as you're changing an instance variable which was originally populated via a parameter.
You could wrap the value in a mutable class, pass a reference to an instance of that class into MyClass2, and then mutate the object within MyClass2 - that change would be seen within your first class, because that would be changing the data within the object rather than the instance variable of MyClass2. It's hard to know whether or not that's actually a good solution though, as we have so little context - with names like MyClass and myMethod we have no clue as to the bigger picture of what this is trying to achieve.
In your first solution the value of the enumeration inside the class didn't change because enumeration is a value type, and this line:
_myParameters = paramParameters;
made a copy of paramParameters and _myParameters is a completely separate, standalone object.
In your second example, MyExchangeClass is a reference type, so this line:
_mySelection= paramParameters;
made _mySelection point to exactly the same object as paramParameters reference was referring to.
From the documentation:
Variables that are based on value types directly contain values. Assigning one value type variable to another copies the contained value. This differs from the assignment of reference type variables, which copies a reference to the object but not the object itself.
And an enumeration is a value type, ibidem:
The value types consist of two main categories:
Structs
Enumerations
As far as I know Class and Object are reference type.
I have below method to Change the Value
public void ChangeValue(MyClass classobj)
{
classobj.Number = classobj.Number*2;
}
I invoke the method to double the value
var myClass=new MyClass();
int myNumber = 10;
myClass.Number = myNumber;
ChangeValue(myClass);
And it will be return 20 which is fine as you can interpret it as when you make object of your class then it pass reference to method and it will update the reference values.
but my question is why its not happening for Object type. In other words why when I make object and assign some value to it like below
object myObject = new object();
string sometext = "Some object value";
myObject = sometext;
ChangeValue(myObject)
it wont change the value after executing the method
public void ChangeValue(object objectValue)
{
objectValue = null;
}
I know the parameter of methods are value types but can not understand it have different behavior for two reference type.
You're actually doing two different things here. Object and your MyClass are indeed both reference types, which means you pass a reference to the actual object into the ChangeValue method. However, the reference that you see inside the method is a copy of the reference the caller holds. They point to the same object, so when you manipulate the object in the method the caller of the method can see your changes, but changes to the actual reference inside the method only affect the method itself.
In an attempt to summarise, objects are passed by reference, but those references are passed by value.
In your method
public void ChangeValue(object objectValue)
{
objectValue = null;
}
What you're actually doing is reassigning the reference objectValue, and that reference is a copy of the reference called myObject which the caller has. Because the method only has a copy, it can't affect the caller's reference at all.
There is a way to make this work, you have to pass the reference by reference. Which always gives me a headache, but that's what the ref keyword is for.
public void ChangeValue(ref object objectValue)
{
objectValue = null; // this is the SAME reference as the caller has, so the caller will see this change
}
However then it also has to be called that way:
ChangeValue(ref myObject);
so that it's obvious at the call site that it might come back pointing to a different object. It's important to know that, as you might still have things relying on the old value and end up in a horrible confused mess if references were pointing to different objects unexpectedly.
You pass the objectValue to the ChangeValue(object objectValue) by value and this value is a reference. Then you change this value, but not the value of the myObject.
You have to pass it as ChangeValue(ref object objectValue) to actually pass the value of reference by reference.
It's not a different behavior, you're doing different things
This will work exactly as your object example:
public void ChangeValue(MyClass classobj)
{
classobj = null;
}
And this will work as your first example(assuming you will pass MyClass instance):
public void ChangeValue(object objectValue)
{
((MyClass)objectValue).Number *= 2;
}
What realy happens here is that when you are assigning parameter (not a property or field of parameter) you are only changing that parameter's value. Original value and variable in calling code stay intact.
The same happens here:
MyClass a = new MyClass();
MyClass b = a;
a = null;
// b still contains the value created in the first line
Simply speaking, reference variables hold the pointer (memory address) of the actual value.
By changing variable's value, you are making it point to different object or null.
But when you are doing a.field=2 this means you are taking the object a is referencing to and changing it's field member value.
public void MethodSample1(Itest variable)
{
variable.TestString = "some sample data";
Itest var1 = variable;
Console.WriteLine(variable.TestString);
MethodSample2(variable);
Console.WriteLine(variable.TestString);
Console.WriteLine(var1.TestString);
}
public void MethodSample2(Itest variable)
{
variable.TestString = "testdata";
}
public interface Itest
{
string TestString { get; set; }
}
Expected both the console output lines print "some sample data" but it seems that TestString is being overwritten with the new value? is it not like "by default in C# all the values are passed by value?".
In short, how to preserve the value of "TestString" in MethodSample1?
(I ran into this problem because all my projects are based upon a single interface)
Even after preserving the value, it does reflect! strange!
For your current problem, I don't think you can prevent any method from modifying the parameter passed to it.
Your variable is a reference type object, In C# reference type's address is passed by value to a method, that is why you are seeing the change. For example if your method is written like:
public void MethodSample2(Itest variable)
{
variable = null;
}
You won't see the change in your MethodSample1 method, since the reference address is passed by value.
is it not like "by default in C# all the values are passed by
value?".
Value types are passed by value, in your case variable is a reference type.
You should see Parameter Passing C# by Jon Skeet
Not sure why you have to modify the passed object, For workaround you can create a temporary copy of the property and then set that value before existing from the method.
The parameter is indeed passed by value, but the value you are passing is a reference to the original object.
If you want to preserve the original object's properties, you'll need to pass a copy of the original object. You could add a Clone() method to the interface or something similar:
public interface ITest
{
string TestString { get; set; }
ITest Clone();
}
public class Test : ITest
{
string TestString { get; set; }
ITest Clone() {
return new Test() {
TestString = this.TestString
};
}
}
Or, you could rethink your current approach. Do you really need to change the property of the interface? Or could you use a variable of type string instead?
how to preserve the value of "TestString" in MethodSample1?
Store it in a local variable.
public void MethodSample1(Itest variable)
{
variable.TestString = "some sample data";
string localTestString = variable.TestString;
Console.WriteLine(variable.TestString);
MethodSample2(variable);
variable.TestString = localTestString;
Console.WriteLine(variable.TestString);
}
But, this is wrong way of doing things. If you tell a little more what do you want to achieve, we could help more.
What is the best way of the following 2 suggestions to modify a property on an object that is being modified by a class that accepts the object as a parameter?
Have the class work on the object and a return a value which you then assign to the object
or.
Pass the object in using the ref keyword and have the class amend the object without actually returning anything.
For example, I have a Person object with a First Name and Last Name and 2 different ways to create the Full Name.
Which is the best way?
public static void Main()
{
Person a = new Person { FirstName = "John", LastName = "Smith" };
Person b = new Person { FirstName = "John", LastName = "Smith" };
NameProcesser np = new NameProcesser();
// Example A
a.FullName = np.CreateFullNameA(a);
// Example B
np.CreateFullNameB(ref b);
}
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName { get; set; }
}
public class NameProcesser
{
public string CreateFullNameA(Person person)
{
return person.FirstName + " " + person.LastName;
}
public void CreateFullNameB(ref Person person)
{
person.FullName = person.FirstName + " " + person.LastName;
}
}
You don't need ref. Just modify the object in your method.
When an reference type is passed as a parameter, it is passed "by reference", not by value. So when you modify it, you're actually modifying the original object. You only need ref if you are passing a value type such as an int.
I say "by reference" in quotes, because what is actually happening is that an internal "pointer" to the original object is being passed by value.
First things first
The fact that you're mentioning ref suggests that you are missing a fundamental notion; that is, code that can access a reference to an object can by definition have access to the actual object.
The only conceivable usage scenario in which you would use a ref parameter is when you want to set that reference to some other object, or to null.
If you don't use ref (or even out for that matter, see the difference here) you are actually passing your argument by value, which means that a copy of it is created.
This means two things, depending on whether the parameter is a value type (like int, long, float etc) or a reference type (reference to an instance of whatever class).
If a parameter is a value type, a copy of it will be created. Your method can then do whatever it wants to it, because the copy is only limited to that method's scope.
If a parameter is a reference type, however (as your Person would be), only the reference itself gets copied: the underlying object is the same. This is where the big difference lies. Keep in mind, however, that the reference you have available inside the method is still a copy of the original one, which means that you can set it to null, set it to another object and, in short, do whatever you like with it: once the method has returned, that reference will disappear, and the original one will be left untouched.
That being said
As others told you, there's really no need to use ref.
Moreover, as long as you're dealing with trivial cases such as concatenating first and last name, I would let the object itself do it (exactly like Slapout did).
There's always time to separate responsibilities later should such a need arise.
Consider also that having a separate class for such a trivial task might be also considered counterintuitive.
Say this is the code at hand:
var p = new Person() { FirstName = "John", LastName = "Smith"} ;
Console.WriteLine(p.FullName);
When I do that, I fully expect FullName to return something meaningful (i.e. "John Smith") at all times.
With both your approaches, instead, what will happen if I forget (and I will) to call CreateFullName?
Should you really need to move a given concern into a separate class, hide it inside the property's get method.
That way, people won't need to know about the underpinnings of the classes you wrote, and it's still testable.
Neither - and you don't need 'ref' - just use:
public void CreateFullNameB(Person person)
{
person.FullName = person.FirstName + " " + person.LastName;
}
At first, the only reason to separate the method into a other class is if that method have dependencies like database or network access. Otherwise that simple method should be a property of Person class.
Also it is only reason to pass whole object to method is when object data is widely used inside that method. Otherwise it is better to pass FirstName and LastName as parameters and return result.
Classes don't need to be passed with ref modifier to modify their content. ref is only required if method want assign parameter with a reference to a new instance.
In example you described if choose from two options the return value is better because it makes less coupling and separates logic from data representation. But if few properties of an entity can be updated, then passing object is better.