Issue with Treeview item update when passing as a parameter - c#

I have following test code, I am updating m_ClientTreeView by calling createTreeView(TreeView tree) method by passing it. But even treeview is a refrence type, the change is not reflecting back. I checked with ref and it is working properly.
namespace TestRefType
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
ClientGUI objCGUI = new ClientGUI();
createTreeView(objCGUI.m_ClientTreeView);
//createTreeView(ref objCGUI.m_ClientTreeView);
objCGUI.m_ClientTreeView.Dock = DockStyle.Fill;
}
private void createTreeView(TreeView tree)
{
tree = new TreeView();
tree.Visible = false;
}
}
public struct ClientGUI
{
public System.Windows.Forms.TreeView m_ClientTreeView;
}
}
What might be the reason?

Although TreeView is a reference type but it doesn't mean you can change its reference when you pass it to a method.
When you pass a reference type to a method, you can change its members but you can not change reference of object. To change the reference of the object you need to use ref keyword in method signature and when passing the instance to the method.
Without using ref, when you pass objCGUI.m_ClientTreeView to createTreeView(TreeView tree) to method, in the method, tree is just a variable which points to a TreeView. You can access and change tree.SomeProperty, but if you say tree = new TreeView() then you just said the tree variable in your method scope point to a new TreeView. Outside of the method, objCGUI.m_ClientTreeView contains the value which it had before passing to the method.
Example
Here is a really simplified example about what you did:
TreeView t1 = null;
TreeView t2 = t1;
t2 = new TreeView();
What do you expect from t1 now?
Note 1: When using a reference type in a structure, you should be careful when using the structure. Although structures are value type but when copying, their reference types don't copy and keep the same references between different instance of that structure, for example if you add node to the TreeView of the copied structure, the node also will be added to the first instance of your structure.
Note 2: Here is a great article by Joseph Albahari about reference type and value type. It probably will solve most of your problems about the concept:
C# Concepts: Value vs Reference Types

Related

Navigating between ContentPages with Prism in Xamarin Forms maintains NavigationParameters

Using the NavigationParameters collection within Prism, we are passing an object from one ContentPage to another ContentPage which displays as a modal.
The modal allows a user to edit the data. If the user decides to cancel the edit form, we call:
NavigationService.GoBackAsync(null, true).
Once navigated back to the previous page, the original property that was passed through to the modal has updated with the edited values without setting it.
Are NavigationParameters passed as a reference within NavigateAsync? What’s the best way of preventing this from happening?
Using the NavigationParameters collection within Prism, we are passing an object [...] [Emphasis mine]
You are setting an object in the NavigationParameters. Instances of classes (objects) are passed by reference in C#, instances of structures are passed by value. For structures there are semantics to copy and compare values (i.e. all public properties are copied and compared respectively), but for classes there are no similar semantics.
Please see the documentation:
Because classes are reference types, a variable of a class object holds a reference to the address of the object on the managed heap. If a second object of the same type is assigned to the first object, then both variables refer to the object at that address.
In order to prevent the original object being updated, you'll have to copy the object before it is manipulated (I'd copy it before passing it, but you could copy it at the target site, too). If your class contains value type properties only, a shallow copy will suffice, i.e. you create a method (or property, but this might be misleading) that returns a new object of your class with all the values copied
class MyClass
{
int Value1 { get; set; }
float Value2 { get; set; }
public MyClass Copy()
{
var copy = new MyClass()
{
Value1 = this.Value1,
Value2 = this.Value2
}
return copy;
}
}
If you object contains reference types itself, you might have to create a deep copy
class MyClass
{
MyClass2 Reference { get; set; }
public MyClass Copy()
{
var copy = new MyClass()
{
Reference = this.Reference.Copy()
}
return copy;
}
}
Of course, those will have to implement a Copy() method, too.

Visibility inside a class of objects created locally

Here it is a sample code in Windows Forms:
namespace WindowsFormsApplication1
{
public class contained
{
public int value;
}
public class container
{
public List<contained> c1 = new List<contained>();
public void add_contained()
{
contained tmp = new contained();
tmp.value = 1; // some default value
c1.Add(tmp);
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
container cnt = new container();
cnt.add_contained();
int i = cnt.c1[0].value; // this works, why?
}
}
}
Practically, I have a big class "container" that manages a list of complex objects "contained". There is a procedure adding a new blank object to the list - to be modified later. Now, I ran the code above and it works, but I do not understand well why.
If the procedure "add_contained" to add a default object to the list creates one locally, I expect it disappear when the procedure exits, so the list should remain with a null pointer. Instead, I can still access the object in the list, as indicated in the last line "int i=...".
Actually, I read the garbage collector is non deterministic, it is unclear what it means, it seems it does not do things in precise moments. But, that means the above code works because it is short? If I accessed the list a bit later (ie in a more complex program) it could not work?
What is the correct way to solve the problem outlined by the code above? Thanks.
When you do new contained() a new object is created and stored "somewhere".
Then a reference to it is assigned to tmp.
That same reference is in turn added to the list and you exit the method.
At that point the variable tmp is "destroyed" but the object is still in memory (because it's still referenced through the List).
If at some point you remove the list item, the reference on that object ; and there are no other reference on that object ; it becomes eligible for collection, meaning the GC can free it's memory.

Why is the parameter is not updated?

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

How to access constructor variables into the methods with in the same class in c#

Here is my code.i am not able to access constuctor value in the function.
public partial class ForgotPassword : UserControl
{
private string mobile_num2 = "";
public ForgotPassword(string _mobile_num)
{
mobile_num2 =_mobile_num;
MessageBox.Show(mobile_num2);//Getting Value here
InitializeComponent();
}
private void btn_submit_Click(object sender, RoutedEventArgs e)
{
string val_conf_pwd;
string conf_pwd = txt_new_conf_pwd.Password;
val_conf_pwd = c.validate_conf_Password(pwd, conf_pwd);
if (val_conf_pwd == "success")
{
MessageBox.Show(mobile_num2);//Getting Null Value Here
}
}
}
If this is your actual code (and it's not just that you actually declared another local variable within your constructor instead of assigning the value to the field) then I suspect the problem is that the instance that btn_submit_Click is being invoked on isn't the same one as the one you're constructing with the non-null value.
So you need to look at where you're constructing any instances of ForgotPassword - you won't be able to just construct a new instance and hope that it will have the same mobile_num2 value as an existing instance, unless you explicitly pass the right value to the constructor.
(As an aside, I'd encourage you to use more conventional names for methods and variables - just camelCase without underscores. But obviously that's not part of what's going wrong.

How to use ref in C#

I've created a class that takes in an object as a parameter by ref. When it takes this object in it's construct it is null. Why does it stay null (uninitialized)?
// example code, not real
class Test{
object parent;
public Test (ref object _parent)
{
parent = _parent;
}
}
object n = null;
Test t = new Test (ref n);
n = new Something ();
When I tried it with a different class (http://pastebin.com/PpbKEufr), it stayed null
Yes, parent will stay null regardless of what you eventually assign to the variable n. The ref keyword will pass the actual reference to n (as opposed to a copy of it) into your method, and is typically used if your method was intended to assign a new object instance to the parameter.
Inside your method, you are making a copy of the reference that n points to, in this case null. When the method completes both n and parent point to null. When later you assign to n, you haven't changed the object to which n and parent point, rather you have asked n to point to a new location, leaving parent still pointing to null.
If you were to create an instance of an object and assign it to n, then parent would point to the same object and any changes to that object's properties would be visible to your class. The same would be true if you did not pass the parameter as ref, as the reference copy also would point to the same object instance.
Hope that helps.
It is not possible to change a private member of a class that way as this would break the idea of encapsulation.
In order to change (i.e. replace) an object stored in a private field you must do so explicitly via a public property or method of that class, e.g.
class Test
{
object parent;
public Test (ref object _parent)
{
parent = _parent;
}
public object Parent
{
get { return parent; }
set { parent = value; }
}
}
object n = null;
Test t = new Test (ref n);
n = new Something ();
t.Parent = n;
This way the language makes sure that data of an object cannot (accidentally) be changed from the outside, which might lead to the strangest effects.
The ref arguments in C# refer to the instance "pointed" by the argument.
For example, if you'd change _parent in the constructor and store it in other instance, then n would change too.
In the posted code you're copying the referenced instance (null) into parent. Meaning, it copies the referenced instance into the field and not the reference of the argument itself.
For example, method that changes the ref argument:
public void M(ref object arg)
{
arg = new object();
}
And a usage example:
[Test]
public void SetReferenceArgument()
{
var myClass = new MyClass();
object arg = null;
myClass.M(ref arg);
Assert.That(arg, Is.Not.Null);
}
ref argument lets us assign an instance into the argument which will change the reference both in the of the method and in the context of the caller.

Categories

Resources