c# class variable still null after calling function - c#

After calling func1 variable mydata stays null. In debug mode I see that in func3 it sets data to string. why it doesn't pass value after exiting function?
Class example
class myclass
{
public string mydata;
public int func1()
{
//....
func2(/**/, mydata);
//....
return 1;
}
private int func2(/**/,data)
{
byte[] arr = new byte[1000];
//...
func3(arr,data);
//...
return 1;
}
private void func3(byte[] arr, string data)
{
char[] a = new char[100];
//...
data = new string(a);
}
}

By default, parameters are passed by value; it means that what is passed is actually a copy of the variable (which is a copy of the reference in the case of a reference type like string). When func3 assigns data, it only modifies a local copy of the variable.
Now, if you change func2 and func3 signatures so that data is passed by reference, you will get the expected result:
public int func1()
{
//....
func2(/**/, ref mydata);
//....
return 1;
}
private int func2(/**/,ref string data)
{
byte[] arr = new byte[1000];
//...
func3(arr, ref data);
//...
return 1;
}
private void func3(byte[] arr, ref string data)
{
char[] a = new char[100];
//...
data = new string(a);
}
I suggest you read Jon Skeet's article about parameter passing for more details.

First, it's an instance variable, not a class variable. To be a class variable it would have to be declared static.
Second, why do you hand it down as an argument to the respective functions? The way you're doing it, it creates a separate string in every method and doesn't refer to the original one. Just go ahead and call it directly:
private void func3(byte[] arr)
{
//...
mydata = new string(a);
}

It because all arguments are passed by reference into the method. data = new string(a);
crates new instance of a string with new reference.
var o = new object(); // reference 1
function void method(object something)
{
// here we have reference to something in stack, so if we will assign new value to it, we will work with stack copy of a reference.
something = null; // we removed reference to something in method not initial o instance
}

You're passing the reference to the string mydata by value. This means mydata will still refer to the same object after the function returns, regardless of what you do inside the function. If you wanted to change the string mydata, you could pass the reference by reference:
public int func1()
{
//....
func2(/**/, ref mydata);
//....
return 1;
}
private int func2(/**/, ref string data)
{
byte[] arr = new byte[1000];
//...
func3(arr, ref data);
//...
return 1;
}
private void func3(byte[] arr, ref string data)
{
char[] a = new char[100];
//...
data = new string(a);
}

Related

Are binary tree nodes passed by reference?

static int GetCount(BinTreeNode<int> L)
{
int count = 0;
while (L != null)
{
count++;
L = L.GetRight();
}
return count;
}
I have the method GetCount().
Now, BinTreeNode is a class that has the members: right, left and info.
for some reason, in the main function
static void Main(string[] args)
{
var t2 = new BinTreeNode<int>(null, 1, new BinTreeNode<int>(null, 2, new BinTreeNode<int>(null, 3, null)));
//Console.WriteLine(TreeLessThanTree(t1, t2));
Console.WriteLine(GetCount(t2));
Console.WriteLine(t2.GetInfo()); // this prints 1
Console.ReadKey();
}
This is weird, since in the function GetCount(), L (which is passed by reference) is changed to null.
Why wasn't t2 passed by reference? Why didn't t2 change?
The reference is passed by value. Meaning: the value of t2 is essentially just a pointer that happens to be the address of an object; when it is passed by value, the pointer (i.e. 4 or 8 bytes) is copied and passed in. It doesn't matter what the GetCount does with the local copy of the pointer: the change to the pointer is not observed at the call-site. However, if the method changes the object at the end of the pointer, then those changes will be observable.
The object is passed in the method. Every changes done in the properties of that object will be kept.
However, if you set something else to the local variable in the method, the original object won't be changed. If you want to change the variable, you have to explicitely use the ref keyword.
In example :
public class A
{
public string Foo { get; set; }
}
public class Program
{
// This is a local variable. If you set something else to this one, the original won't be changed
// |
// V
public static void DoSomething(A a)
{
a.Foo = "42"; // <---- This changes the property in the original
a = new A // <---- This sets something to the local variable a
{
Foo = "Hello world"
};
}
// This variable is passed by references. If you set something else to this one, the original will be changed
// | |
// V V
public static void DoSomethingElse(ref A a)
{
a.Foo = "42"; // <---- This changes the property in the original
a = new A // <---- This sets something to the original
{
Foo = "Hello world"
};
}
public static void Main()
{
var a = new A
{
Foo = "Bar"
};
DoSomething(a);
Console.WriteLine(a.Foo); // This outputs 42
// notice this --v
DoSomethingElse(ref a);
Console.WriteLine(a.Foo); // This outputs Hello world
}
}

Do anonymous methods passed to actions obtain data by value or reference?

I am creating an anonymous method and passing it into an action to be invoked later on. I would like to pass some numeric data (int) into my anonymous method. In order to pass the data by value, am I required to create copies? Or, will the data be passed by value?
Here is what I think the implementation would look like, if I had to create copies:
private void CreateAction()
{
int bus = 4;
CustomObject[] data = new object[16];
int length = 1500;
this.doWorkLater = new Action(() =>
{
var busCopy = bus;
var dataCopy = data;
var lengthCopy = length;
this.WorkMethod(busCopy, dataCopy, lengthCopy);
});
}
Is this (the above code) necessary in order to get length and bus by value?
In this case, will CustomObject[] data (some class I have created) be passed by reference or by value?
What you pass is not a By-Value Copy.
If you're not going to modify the values before executing the action, then you don't need to worry about how you pass the values. But no they are no passed by value. Even if you return the action and Invoke it from another method. the values are persisted in a class generated by the compiler. No need to worry about that
If you expect the data to change before executing the action then you're doing it wrong. The approach you're using (Copy a Value-Type to a local variable) should be done outside the action and not inside of it. As for the reference type (Array) even if you copy it to a local variable, the reference it copied so any change in the copy local variable is reflected.
private void CreateAction()
{
int bus = 4;
CustomObject[] data = new object[16];
int length = 1500;
var busCopy = bus; // a copy of bus
var dataCopy = data; // reference copy
var lengthCopy = length; // a copy of length
this.doWorkLater = new Action(() =>
{
this.WorkMethod(busCopy, dataCopy, lengthCopy);
});
bus = 10; // No effect on the action
length = 1700; // No effect on the action
this.doWorkLater();
}
This looks pointless, but you may sometimes need to copy a local variable to another local variable before passing it to an anonymous method. Check this Valid Example that fixes a reported unexpected behavior !
Closures capture values observably by reference* - note that code you have does not solve issue for general case, also if whole point of CreateAction is create one single action it will work.
private void CreateAction()
{
int bus = 4;
this.doWorkLater = new Action(() =>
{
var busCopy = bus;
this.WorkMethod(busCopy);
});
// if you change local `bus` before call to `doWorkLater` it will not work:
bus = 42;
doWorkLater(); // busCopy is 42.
}
* It actually collects all variables in a compiler created class and uses reference to it to access variables in a method and closure. Thus even value types look behave as if passed by reference.
This might help you to figure out what's going on.
If you start with this slightly simplified class:
public class Example
{
private void CreateAction()
{
int bus = 4;
object[] data = new object[16];
int length = 1500;
Action doWorkLater = () =>
{
var busCopy = bus;
var dataCopy = data;
var lengthCopy = length;
this.WorkMethod(busCopy, dataCopy, lengthCopy);
};
doWorkLater.Invoke();
}
public void WorkMethod(int bus, object[] data, int length)
{
}
}
...then the compiler produces basically this:
public class Example
{
private void CreateAction()
{
Example.GeneratedClass closure = new Example.GeneratedClass();
closure.parent = this;
closure.bus = 4;
closure.data = new object[16];
closure.length = 1500;
// ISSUE: method pointer
IntPtr method = __methodptr(closure.CreateAction);
new Action((object)closure, method)();
}
public void WorkMethod(int bus, object[] data, int length)
{
}
[CompilerGenerated]
private sealed class GeneratedClass
{
public int bus;
public object[] data;
public int length;
public Example parent;
internal void CreateAction()
{
this.parent.WorkMethod(this.bus, this.data, this.length);
}
}
}
The local variables trapped in the closure cease being local variables to the method and become public fields in the generate class.
Now everything that you know about C# and classes applies.

Self-contained generic memento

Dearest fellow programmers,
I seem to lack some understanding as of how the referencing works in C#.
The case:
I tried to implement some sort of Memento proxy which would wrap an interface and store every parameter that we're provided to the method calls and store these into a list.
Whenever necessary we could call the RestoreState and the objects would "reset" to the original state.
The code:
Consumer and model object
class Program
{
static void Main(string[] args)
{
IMemento memento = new Memento();
PrestationInfo prestationInfo2 = new PrestationInfo { Advance = 2 };
memento.Add(prestationInfo2);
Console.WriteLine(prestationInfo2.Advance); //Expect 2
prestationInfo2.Advance = 1;
Console.WriteLine(prestationInfo2.Advance); //Expect 1
memento.RestoreState();
Console.WriteLine(prestationInfo2.Advance); //Expect 2, but still 1
Console.ReadKey();
}
}
[Serializable]
public class PrestationInfo
{
public int Advance { get; set; }
}
Memento
public interface IMemento
{
void Add(object pItem);
void RestoreState();
}
public class Memento : IMemento
{
public Memento()
{
MementoList = new Dictionary<long, object>();
ReferenceList = new List<object>();
ObjectIDGenerator = new ObjectIDGenerator();
}
private ObjectIDGenerator ObjectIDGenerator { get; set; }
private Dictionary<long, object> MementoList { get; set; }
private List<object> ReferenceList { get; set; }
public void Add(object pItem)
{
bool firstTime;
long id = ObjectIDGenerator.GetId(pItem, out firstTime);
if (firstTime)
{
var mementoObject = DeepCopy(pItem);
MementoList.Add(id, mementoObject);
ReferenceList.Add(pItem);
}
}
public void RestoreState()
{
for (int i = 0; i < ReferenceList.Count; i++)
{
object reference = ReferenceList[i];
bool firstTime;
long id = ObjectIDGenerator.GetId(reference, out firstTime);
if (MementoList.ContainsKey(id))
{
object mementoObject = MementoList[id];
reference = mementoObject;
//reference = PropertyCopy<PrestationInfo>.CopyFrom(mementoObject as PrestationInfo); //Property copy
//Interlocked.Exchange(ref reference, mementoObject); //Also tried this
}
}
}
private static TCopy DeepCopy<TCopy>(TCopy pObjectToCopy)
{
using (MemoryStream memoryStream = new MemoryStream())
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(memoryStream, pObjectToCopy);
memoryStream.Position = 0;
return (TCopy)binaryFormatter.Deserialize(memoryStream);
}
}
}
Extra info
My guess is, I'm doing/understand something wrong regarding the List.
I also tried the Interlocked.Exchange, playing around with "ref"'s, using WeakReference's and storing the object into a CareTaker object (and storing that CareTaker into the List), implement some copy Property thing...
And ... I just can't see it.
My expected result would be the PrestationInfo.Advance property containing the value 2. But it keeps
Try this:
Change the Add method:
public long Add(object pItem)
{
bool firstTime;
long id = ObjectIDGenerator.GetId(pItem, out firstTime);
if (firstTime)
{
var mementoObject = DeepCopy(pItem);
MementoList.Add(id, mementoObject);
ReferenceList.Add(pItem);
}
return id; // i need my memento! LOL
}
You should also add this accessor method:
public object GetRestoredState(long id)
{
return MementoList[id]; // you should put some range check here
}
Now that you have your id, you can fetch the restored state this way:
memento.RestoreState();
prestationInfo2 = memento.GetRestoredState(savedId); // <-- you got this when you called the Add()...
Console.WriteLine(prestationInfo2.Advance); //Expect 2, but still 1
Follow ups: you can also make the IMemento into a IMemento<T>, and adjust your code accordingly
Memento.Add needs a ref parameter modifier to access the original reference type pointer.
https://msdn.microsoft.com/en-us/library/14akc2c7.aspx?f=255&MSPPError=-2147217396
It looks like the problem is in your understanding of references in .NET
public void RestoreState()
{
for (int i = 0; i < ReferenceList.Count; i++)
{
object reference = ReferenceList[i];
bool firstTime;
long id = ObjectIDGenerator.GetId(reference, out firstTime);
if (MementoList.ContainsKey(id))
{
object mementoObject = MementoList[id];
reference = mementoObject;
//reference = PropertyCopy<PrestationInfo>.CopyFrom(mementoObject as PrestationInfo); //Property copy
//Interlocked.Exchange(ref reference, mementoObject); //Also tried this
}
}
}
The RestoreState method above does not return anything, and you're strictly operating on references, not their internal state. Inside your method object reference is a local reference. It is not the same as the external prestationInfo2 and your method simply makes reference point (refer) to the previously saved copy of the state of presentationInfo2.
You could modify it something like this:
public object RestoreState()
{
for (int i = 0; i < ReferenceList.Count; i++)
{
object reference = ReferenceList[i];
bool firstTime;
long id = ObjectIDGenerator.GetId(reference, out firstTime);
if (MementoList.ContainsKey(id))
{
object mementoObject = MementoList[id];
reference = mementoObject;
return reference;
}
}
return null;
}
And then call it like this:
presentationInfo2 = memento.RestoreState();
If you want the memento to track objects and magically restore their state you will have to make the objects themselves aware of the memento which introduces coupling or use reflection to modify the tracked references internal state. Basically you don't deserialize the persisted state into a new object but use reflection to overwrite the previously stored internal state into the tracked object reference.
Be careful though to store references using WeakReference otherwise you will find yourself with a nice case of memory leak.

Altering references within a reference parameter

I am trying to pass an array to a method. The array contains objects which need to be nulled. The method would simply null each object in a loop. I need this to reflect back in the caller.
Sample code (code goodness & minor syntactical issues can be ignored):
public class ABC
{
...
}
private void SomeMethod()
{
var toBeNulledObj1 = new ABC();
var toBeNulledObj2 = new ABC();
var arrayOfNullableObjects = new ABC[]{toBeNulledObj1 ,toBeNulledObj2};
NullingFunction(arrayOfNullableObjects);
}
private void NullingFunction(ABC[] arrayOfNullableObjects)
{
for(int i = 0; i< arrayOfNullableObjects.Length ; i++)
{
arrayOfNullableObjects[i] = null;
}
}
Clearly upon returning, toBeNulledObj1 & toBeNulledObj2 are not null but retain their older values though arrayOfNullableObjects now has two null objects. I realise that ref & out only apply to the collection parameter (here, arrayOfNullableObjects which doesn't even need a ref). I tried passing them in as params instead of a collection but that doesn't help, either (ref & params cannot be combined).
Question: How can I alter each/any object in a collection of objects within a method such that the change is visible to the caller? I am not altering the collection itself. Please note, I am not changing the contents/members of toBeNulledObj1 but the reference itself (to either null or a new object).
Solution #1: Unsafe code
One solution is using a unsafe code. You have to think twice before using it, and I do not know if you will be happy with my answer, but here it is.
static private void SomeMethod()
{
ABC toBeNulledObj1 = new ABC();
ABC toBeNulledObj2 = new ABC();
IntPtr[] arrayOfNullableObjects = new IntPtr[] { MakeReference(ref toBeNulledObj1), MakeReference(ref toBeNulledObj2) };
NullingFunction(arrayOfNullableObjects);
}
static private void NullingFunction(IntPtr[] arrayOfNullableObjects)
{
foreach (IntPtr reference in arrayOfNullableObjects)
ClearReference(reference);
}
/// <summary>
/// Makes the reference to the reference value of a reference type.
/// </summary>
static unsafe private IntPtr MakeReference<T>(ref T value)
where T: class
{
TypedReference reference = __makeref(value);
return *(IntPtr*)&reference;
}
/// <summary>
/// Clears the reference to a reference type, using a reference to that reference value.
/// </summary>
static unsafe private void ClearReference(IntPtr reference)
{
if (sizeof(IntPtr) == 4)
*((int*)reference) = 0;
else
*((long*)reference) = 0;
}
Solution #2: Anonymous class
The second solution could be done by using an anonymous class which holds your data. The fields inside this anonymous class are cleared. A disadvantage is that you have a second class and the reference to this class also should to be cleared. (This can be done by adding ref to o and in the NullingFunction set o to null.) Of course you can also use a predefined class, but his solution is the closest to your code in your OP.
public static void SomeMethod()
{
var container = new
{
toBeNulledObj1 = new ABC(),
toBeNulledObj2 = new ABC(),
};
NullingFunction(container);
}
private static void NullingFunction<T>(T container)
where T : class
{
if (container == null)
return;
foreach(FieldInfo f in container.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic))
if (f.FieldType.IsClass)
f.SetValue(container, null);
}
When you say you want to set them to null, do you mean that you want to destroy the object?
C# has automatic garbage collection, so as soon as an object goes out of scope (that is, when no other objects make reference to it), the garbage collector will destroy it.
In the code above, the label "tobeNulledObj1" still refers to an object, and your array also points to it before you call the NullingFunction.
After you call the NullingFunction, you still have one reference pointing to the object (that is, tobeNulledObj1). If you set tobeNulledObj1 to null, then the Garbage Collector will collect it.
EDIT: I second cheedep's question - what is it exactly that you are trying to do? What do you want your variables to hold at the end?
If function A holds a reference to a variable i.e:
var toBeNulledObj1 = new ABC();
var toBeNulledObj2 = new ABC();
And does not pass this into function B:
private NullingFunction(ABC[] arrayOfNullableObjects)
Then there is nothing that function B can do to change the reference that toBeNulledObj1 / 2 points to.
Since ref is not allowed along with params (as you mentioned):
private void NullingFunction(ref params ABC[] arrayOfNullableObjects)
{
for (int i = 0; i < arrayOfNullableObjects.Length; i++)
{
arrayOfNullableObjects[i] = null;
}
}
The available alternative is to create overloads e.g.:
private void SomeMethod()
{
var toBeNulledObj1 = new ABC();
var toBeNulledObj2 = new ABC();
NullingFunction(ref toBeNulledObj1, ref toBeNulledObj2);
Console.ReadKey();
}
private void NullingFunction(ref ABC one)
{
one = null;
}
private void NullingFunction(ref ABC one, ref ABC two)
{
one = null;
two = null;
}
Is wrapping acceptable?
class Wrapped<T> where T : new() {
private T val = new T();
...
public void Nullify() { val = null; }
}
private void SomeMethod()
{
var toBeNulledObj1 = new Wrapped<ABC>();
var toBeNulledObj2 = new Wrapped<ABC>();
var arrayOfNullableObjects = new Wrapped<ABC>[]{toBeNulledObj1 ,toBeNulledObj2};
NullingFunction(arrayOfNullableObjects);
Debug.Assert(toBeNulledObj1.Get() == null);
// Or...
Debug.Assert(toBeNulledObj1.IsDefined == false);
// Or...
Debug.Assert(toBeNulledObj1.IsNull == true);
}
private void NullingFunction(Wrapped<ABC>[] arrayOfNullableObjects)
{
for(int i = 0; i< arrayOfNullableObjects.Length ; i++)
{
arrayOfNullableObjects[i].Nullify();
}
}
(Disclaimer: hand-compiled code :) may contain errors)
If you need it as a general pattern, you can make NullingFunction parametric (T, U), with a constaint where U: Wrapped<T>
The idea is to make something similar to Nullable for ref types, or something that looks like a smart pointer, if you are familiar with C++.
Thus, wrapper could have T Get() (or an implicit conversion to T) to get out the value, an IsDefined property, and so on.

Send multiple objects between threads using invoke in c#

I'm having problems with passing loaded data from one thread to another to add the data to the form. I added another object into "var obj = new object[] { names }" and got "Parameter count mismatch". I'd still prefer to pass "Clients" and "Messages" from "LoadData()" in the second thread to "UpdateFormMethod()" in the first one, but I have no idea how to do it. I'd be grateful if anyone could help me with this problem.
Here's the important part of the code within one class:
private readonly Thread _thread;
public readonly Loader Loader = new Loader();
public Dictionary<string, Client> Clients;
public Dictionary<string, Message> Messages;
private bool _stopData = false;
public delegate void UpdateForm(object data);
public UpdateForm MyDelegate;
public Fcon() {
InitializeComponent();
MyDelegate = new UpdateForm(UpdateFormMethod);
_thread = new Thread(LoadData);
_thread.Start();
}
public void UpdateFormMethod(object data) {
foreach (var str in ((IEnumerable<string>)data).Where(str => !fcon_container_users_list.Items.Contains(str))) {
fcon_container_users_list.Items.Insert(0, str);
}
}
public void LoadData() {
while (!_stopData) {
Clients = Loader.GetClients(Operator);
Messages = Loader.GetMessages(Operator);
var status = Loader.SetStatus(Operator);
var names = new string[Clients.Count];
var x = 0;
foreach (var kvp in Clients) {
names[x] = "user_" + kvp.Value.id_fcon_client;
x++;
}
var obj = new object[] { names };
this.Invoke(this.MyDelegate, obj);
Thread.Sleep(1000);
}
}
public void StopData() {
_stopData = true;
}
It sounds like you're not entirely clear where the signature is coming from. It's your own delegate - if you want to change the signature, just change the signature of the delegate and the method implementing it:
public delegate void UpdateForm(IEnumerable<string> data, int foo);
...
public void UpdateFormMethod(IEnumerable<string> data, int foo) {
foreach (var str in data.Where(str =>
!fcon_container_users_list.Items.Contains(str))) {
fcon_container_users_list.Items.Insert(0, str);
}
}
Then:
var obj = new object[] { names, someIntVariable };
this.Invoke(this.MyDelegate, obj);
Or more simply:
this.Invoke(this.MyDelegate, names, someIntVariable);
I'd probably use the existing Action<T>, Action<T1, T2> delegates rather than creating new ones though OR T Func<T1 [,T2]> if you require a return type.
you are passing an object [] in but you should only pass in object.
To send it in just cast it as object i.e.
this.Invoke(this.MyDelegate, (object)obj);
and cast it back inside the method. The reason they specified object as the parameter type is that it allows them not to have to specify many many signatures I think

Categories