So basically I have a class NodeTree:
public class NodeTree
{
public NodeTree(int value, NodeTree left, NodeTree right)
{
Value = value;
Right = right;
Left = left;
}
public int Value { get; set; }
public NodeTree Right { get; set; }
public NodeTree Left { get; set; }
}
And in my main I want to do something like
NodeTree root = null;
Algo.InsertValueIt(root, 8);
Where InsertValueIt() is a method from my static class Algo which does :
public static void InsertValueIt(NodeTree root, int val)
{
var newNode = new NodeTree(val, null, null);
if (root == null)
{
root = newNode;
}
}
Everything is working as expected in my method, but back to my main, my object root is still null.
The reason I am confused is that I give to my method a reference, so it should modify the value of the adress to the new space I am allocating.
I think I can solve my problem by just returning a NodeTree, but is there a way of doing it with a void return type?
You need to define your argument to be passed by reference in order to modify the original value (note the ref keyword):
public static void InsertValueIt(ref NodeTree root, int val) {
...
Also when calling the method, you need to mark the parameter with ref:
Algo.InsertValueIt(ref root, 8);
... otherwise you only modify the local copy in that function.
What happens when you pass a reference type to a method?
The variable declared to be of a reference type holds the memory address where the instance of the type has been allocated (the root in the calling code). The value of this address is copied to a new variable created on the stack for the called method (the root in the InsertValueIt). Using that address through the new variable you will be able to change every public property of the instance or call any methods (provided that the address passed is not null).
What happens now if you call new on this local variable?
A new block of memory is allocated on the heap for the type, the constructor is called to initialize everything, and the memory address of this block is stored in the LOCAL variable inside the InsertValueIt.
Your original one, (the root in the calling code), is unaffected by this change. (still holds null). Using the ref keyword makes the this 'problem' disappear, but I suggest to use a method that creates the Node and return it to the calling method instead.
If you want to understand in more depth this subject I recommend these two articles:
C#Concepts: Value Types vs Reference Types from Joseph Albahari
Parameter Passing in C# from Jon Skeet
Your root value assigned in InsertValueIt is not used in any execution path, so you should add the ref keyword in the parameter declaration
Related
In implementing a Service Locator, I've come across something I'm confused about with regards to reference types.
In the code below, I have a static class ServiceLocator which exposes 2 static methods, GetService and ProvideService - get returns the current service, and provide takes a new service as an argument and assigns it to the current service variable. If the provided service is null, it assigns currentService to a static defaultService initialised at the start of the class declaration. Simple stuff:
public static class ServiceLocator {
private static readonly Service defaultService = new Service();
private static Service currentService = defaultService;
public static Service GetService() {
return currentService;
}
public static void ProvideService(Service service) {
currentService = service ?? defaultService;
}
}
What i'm confused about is this: I have a separate class which stores a reference to the currentService at the start of its class declaration in the variable named referenceToCurrentServiceAtStart. When I provide the service locator with a new Service instance to update the current service, referenceToCurrentServiceAtStart appears instead to maintain the reference to defaultService:
public class ClassThatUsesService {
private Service referenceToCurrentServiceAtStart = ServiceLocator.GetService();
private static ClassThatUsesService() {
ServiceLocator.ProvideService(new Service());
// this variable appears to still reference the defaultService
referenceToCurrentServiceAtStart != ServiceLocator.GetService()
}
}
So the references appear to follow this kind of chain:
referenceToCurrentServiceAtStart -> defaultService -> (Service in memory)
Which is understandable, since referenceToCurrentServiceAtStart simply copies the currentService reference. However, the behaviour I'm looking for/would like is for referenceToCurrentServiceAtStart to always reference whatever currentService references, so it's updated by Provide(). Something more akin to:
referenceToCurrentServiceAtStart -> currentService -> (Service> in memory)
So, is this behaviour possible? I'm really unsure of how I'd achieve this kind of reference behaviour. I'm new to C# so it's very possible there's some obvious language feature I'm clueless about. Any help would be greatly appreciated.
is this behaviour possible?
No, not as you've described it. As you're already aware, all you get is a copy of the original reference. Changing the original reference doesn't change the copy, any more than copying the value of an int variable to another would allow you to later change the original and have the copy change:
int original = 17;
int copy = original;
original = 19;
// "copy" is still 17, of course!
If you want to always have the current value of the reference in ServiceLocator, then you should just always retrieve the value from that class, rather than using a local field. In your above example, you might indirect through a property, e.g.:
public class ClassThatUsesService {
private Service referenceToCurrentServiceAtStart => ServiceLocator.GetService();
}
It's a one character change (the = becomes =>), but don't be fooled. It's a significant change in implementation. What you wind up with instead of a field, is a read-only property (i.e. has only a get method and no set method), where that property's get method calls the ServiceLocator.GetService() method and returns the result.
Personally, I wouldn't bother. Unless you have some very strong expectation that the implementation of referenceToCurrentServiceAtStart will change in the future, you should just call ServiceLocator.GetService() directly. Don't even have the referenceToCurrentServiceAtStart property. Since the code expects to always get the current value, the best way to ensure that is to just always get the current value, straight from the class where that value is stored.
Finally, I'll take the opportunity to show a scenario that is similar to what you're asking, but not exactly. In particular, because you're trying to store the reference in a class field, the above is how you need to do it. But, the latest C# has "reference return values", which must be stored in "ref locals". Since you want to reference a static field, which is guaranteed to always exist, you can in fact return a reference to the field, store that in a local, and when you retrieve the local variable's value, it will always have whatever is in the field, because it's a reference to the field, not a copy of it.
You can see the example in the documentation (see links above), but here's another example that is more similar to what you're doing:
class Program
{
static void Main(string[] args)
{
// stores a reference to the value returned by M1(), which is to say,
// a reference to the B._o field.
ref A a1 = ref B.M1();
// Keep the original value, and create a new A instance
A original = a1, a2 = new A();
// Update the B._o field to the new A instance
B.M2(a2);
// Check the current state
Console.WriteLine($"original.ID: {original.ID}");
Console.WriteLine($"a1.ID: {a1.ID}");
Console.WriteLine($"a2.ID: {a2.ID}");
}
}
class A
{
private static int _id;
public int ID { get; }
public A()
{
ID = ++_id;
}
}
class B
{
private static A _o = new A();
public static ref A M1()
{
// returns a _reference_ to the _o field, rather than a copy of its value
return ref _o;
}
public static void M2(A o)
{
_o = o;
}
}
When you run the above, you'll get this output:
original.ID: 1
a1.ID: 2
a2.ID: 2
In other words, the variable a1 winds up yielding the same value found in a2, which is the new object passed to the B.M2() method to modify the B._o field, while the original copy of the B._o field value remains a reference to the original object that field referenced.
This doesn't work in your case, because the ref value that's returned has to be stored in a ref local. You can't put it into a class field. But it's similar enough to your scenario that I wanted to mention it, in case you want to change your design to allow that, or want to use that technique in some other scenario that does work in that way.
Consider following code, I am trying to implement custom link list.
Expected Output : Start-->123-->11-->NULL
Actual Output : Start-->11-->NULL
class MyLinkList
{
public object data { get; set; }
public MyLinkList Next { get; set; }
}
public static void PrintLinkList(MyLinkList start)
{
Console.Write("Start-->");
while (start != null)
{
Console.Write(start.data + "-->");
start = start.Next;
}
Console.Write("NULL");
}
public static void AddNodeStart( MyLinkList start, object data)
{
MyLinkList newNode = new MyLinkList();
newNode.data = data;
newNode.Next = start;
start = newNode;
}
public static void Main()
{
MyLinkList n = new MyLinkList() { data = 11, Next = null };
AddNodeStart( n,123);
PrintLinkList(n);
Console.ReadLine();
}
The problem is even though node is added to the list in the AddToStart function, its value is not persisted when control come back to main function.
Object is passed by reference then why its value is not getting persisted. if I use 'ref' word then I get the expected result.
Atul sureka
Add ref to your method declaration like so:
public static void AddNodeStart(ref MyLinkList start, object data)
then call it
AddNodeStart(ref n,123);
and it should work.
If you don't, then start is just a variable inside AddNodeStart method - assigning values to it will not change reference stored in n.
That said it is rather a bad taste to do this. Instead consider returning the new node from your add method.
public static MyLinkList AddNodeStart(MyLinkList start, object data)
{
MyLinkList newNode = new MyLinkList();
newNode.data = data;
newNode.Next = start;
return newNode;
}
then call it this way:
n = AddNodeStart(n,123);
Because the reference in C# (also in Java) is passed by value. The actually reference used in the method is the copy of the reference value passed in. (The object being referred is not copied)
Another example is you can't swap 2 objects by passing the references into a method. Since all references are passed by value, what you actually swap is the values of the copied references.
Go the answer from Why use the 'ref' keyword when passing an object?.
Value is not getting persisted because I am creating a new object in AddNodeStart. If I modify the existing object in the function then the changes would be persisted.
This might seem like a CS101 question, but I've managed to thoroughly confuse myself.
//this is inside a service class
ObjectToUpdate objectToUpdate = objectrepository.Get(objectToUpdate.Id);
SecondObject secondObject = secondObjectRepository.Get(secondObject.Id);
objectToUpdate.Update(secondObject);
objectRepository.Save(objectToUpdate);
//the object itself
public class ObjectToUpdate {
public int Id { get; set; }
public string Name { get; set; }
public void Update(SecondObject secondObject) {
Name = secondObject.Name
}
}
When I get to the "Save" line, it will correctly have updated the objectToUpdate with the name from the secondObject, correct? It carries a reference to itself when you pass it to the Update method?
Yes, classes are passed around by reference, so you will be passing a reference to the same object. This tutorial provides a great reference for understanding this concept: http://www.c-sharpcorner.com/UploadFile/rmcochran/csharp_memory01122006130034PM/csharp_memory.aspx?ArticleID=9adb0e3c-b3f6-40b5-98b5-413b6d348b91&PagePath=/UploadFile/rmcochran/csharp_memory01122006130034PM/csharp_memory.aspx
That looks correct to me. When you get to the Save() line, objectToUpdate.Name will be the same as secondObject.Name
If it is easier to read logically, you could change this line to include "this."
this.Name = secondObject.Name
so that you realize that the Name property being set is the one that belongs to 'this' which is the same object instance that the method was called on. The code is functionally identical, but might be easier to comprehend?
Yes, the value of a .NET Object is actually the memory address where that object is stored. Saying firstObject = secondObject wouldn't affect the secondObject referenced in the calling method, but saying firstObject.Name = secondObject.Name will change the value of the Name.
Could you please explain the following behavior of C# Class. I expect the classResult as "Class Lijo"; but actual value is “Changed”.
We’re making a copy of the reference. Though the copy is pointing to the same address, the method receiving the argument cannot change original.
Still why the value gets changed ?
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
String nameString = "string Lijo";
Person p = new Person();
p.Name = "Class Lijo";
Utilityclass.TestMethod(nameString, p);
string classResult = p.Name;
Response.Write(nameString + "....." + classResult);
}
}
public class Utilityclass
{
public static void TestMethod(String nameString, Person k)
{
nameString = "Changed";
k.Name = "Changed";
}
}
public class Person
{
public string Name
{
get; set;
}
}
Update: When I pass a String, it does not get actually changed.
The briefest answer is: read my article on parameter passing which goes into this in a fair amount of detail.
The slightly longer answer is to compare these two methods, both of which use value parameters:
public void ChangeMe(string x)
{
x = "changed";
}
public void ChangeMe(Person x)
{
x.Name = "changed";
}
In the first case, you are changing the value of the parameter. That is completely isolated from the original argument. You can't change the content of the string itself, because strings are immutable.
In the second case, you are changing the contents of the object which the parameter's value refers to. That's not changing the value of the parameter itself - it will be the same reference. To give a real world example, if someone delivers something to your house that changes the contents of your house, but it doesn't change your house's address.
If you changed the second method to this:
public void ChangeMe(Person x)
{
x = new Person("Fred");
}
then the caller wouldn't see any change. This is closer to what you're doing with a string - you're making the parameter refer to a different object, rather than changing the contents of the existing object.
Now, when you use a ref parameter, the variable used by the caller as the argument is "aliased" with the parameter - so if you change the value of the parameter, that changes the value of the argument as well. So if we change the last method like this:
public void ChangeMe(ref Person x)
{
x = new Person("Fred");
}
then:
Person y = new Person("Eric");
ChangeMe(ref y);
Console.WriteLine(y.Name);
this will print out "Fred".
The key concept to understand is that the value of a variable is never an object - it's either a value type value or a reference. If an object's data is changed, that change will be visible through other references. Once you understand that copying a reference isn't the same as copying an object, the rest falls into place reasonably easily.
Person is a reference type, so no matter whether you use ref, out or nothing, you will always be able to modify it inside the method. You never pass the real person object to the method, you are passing the pointer as reference but not the actual Person. The ref keyword is useful with value types (such as structs, int, float, DateTime, ...). It could also be used with reference types but only to indicate behavior but cannot enforce it. If you use it with reference types it allows you to change the object this reference is pointing to.
When you pass P to a test method you pass its location in the memory, rather than the copy of the object. Reference gets picked up in the body of the method and the original value gets modified.
Utilityclass.TestMethod cannot change the local variable p to point to a different Person object since you are not passing by reference, but it is still free to call any methods or change any properties on the object it is passed. So the Name property can be modified within Utilityclass.TestMethod.
This question has been mostly answered, but I think you might like to try out this snippet (bonus points if you try this out with ints!)
class Program
{
static void Main(string[] args)
{
Person p = new Person();
p.Name = "Class Lijo";
Utilityclass.TestMethod(p);
string classResult = p.Name;
Console.WriteLine(classResult);
Utilityclass.TestMethod2(ref p);
classResult = p.Name; // will bomb here
Console.WriteLine(classResult);
}
}
public class Utilityclass
{
public static void TestMethod(Person k)
{
k.Name = "Changed";
k = null;
}
public static void TestMethod2(ref Person k)
{
k.Name = "Changed Again!";
k = null;
}
}
When you pass a reference type argument to a method, this means that the method has direct access to that argument not to a copy of it....
So the result is Changed.
How would I get the parent class of an object that has a value of null?
For example...
ClassA contains int? i which is not set to any value when the class is created.
Then in some other place in the code I want to pass in i as a parameter to some function. Using i as the only info, I want to be able to figure out that ClassA "owns" i.
The reason for this is because ClassA also contains some other object, and I want to call this other object's value from that same function mentioned in the above paragraph.
Could also be:
public class A
{
public class B
{
public int? i;
public int? j;
}
B classBInstance = new B();
public string s;
}
{
...
A someClassAInstance = new A();
...
doSomething(someClassAInstance.classBInstance.i);
...
}
public static bool doSomething(object theObject)
{
string s = /* SOMETHING on theObject to get to "s" from Class A */;
int someValue = (int)theObject;
}
You can't. Pass an instance of A to doSomething.
class A is not the Parent (base) of its members. Just their holder.
So you cannot do what you want, passing an int or int? around doe not involve any information about the class.
The parameter that is sent to the method doesn't contain any information that you can use to determine which object it originally came from. What's sent to the method is just a copy of the nullable int, boxed in an object.
So what you are asking for is not possible. The only way to do something like that would be to analyse the call stack to find the calling method, then analyse the code in that method to determine where the parameter value was taken from.
Cant you use a dictionary or keyvaluepairs instead so that the int is linked to "s" that way? The problem is that an int is not aware of which object owns it.
Its not possible since you are passing 'i' which is a member of class B. But class B does not hold a reference to an instance of class A. An instance is required to get the value of 's' since its a non-static field.