1

let's say I've a class to manage a stack of delegates. For some reason, at some point I need to invalidate a random delegate on the stack so, since I pass a variable of a delegate as reference, I expect that setting to null that variable, will prevent the stack to invoke that method just testing if it is null, but instead happens that the reference to the method is still there and therefore will be called. Here some silly code to show what I mean:

public delegate void DlgtVoidVoid(); public class TestPile { Pile pileStack = new Pile(); DlgtVoidVoid _delvar1 = null; DlgtVoidVoid _delvar2 = null; public void Main() { _delvar1 = voidmethod1; _delvar2 = voidmethod2; pileStack.PushItem(ref _delvar1); pileStack.PushItem(ref _delvar2); //trying to invalidate the first delegate handler _delvar1 = null; pileStack.InvokeAndPop();//invoke 2 pileStack.InvokeAndPop();//shouldn't voidmethod1 call fail? //but instead also voidmethod1 will be called: why? } void voidmethod1() { Console.WriteLine("calling void method one"); } void voidmethod2() { Console.WriteLine("calling void method two"); } } 

and this is a little stack manager just for an example:

public class Pile { DlgtVoidVoid[] thepile = new DlgtVoidVoid[10]; int pileindex = -1; public void PushItem(ref DlgtVoidVoid item) { thepile[++pileindex] = item; } public DlgtVoidVoid PeekItem() { return thepile[pileindex]; } public DlgtVoidVoid PopItem() { return thepile[pileindex--]; } public void InvokeAndPop() { if(pileindex >= 0) { if(PeekItem() != null) PopItem().Invoke(); } } } 

It is obvious that passing with ref a reference variable in c# don't work as I would expect, let's say, in C++ or some, therefore is there a way to achieve that in C# or I must change that code logic?

6
  • 1
    ref only applies to the local variable item in PushItem, you are storing a copy of the reference in the stack. When you set _delVar1 to null that does not affect the copied stack reference. Commented Oct 12, 2016 at 14:45
  • Making your parameter for PushItem() by-ref here does no hing. You are still only putting a copy of the reference into thepile. Would suggest some different logic here. Commented Oct 12, 2016 at 14:45
  • What do you expect from setting your delegate to NULL? Not an error probably... Commented Oct 12, 2016 at 14:46
  • voidmethod1 is called, because you only clear the reference from _delvar1 to your function. Your Pile class has still a reference to the function. Commented Oct 12, 2016 at 14:47
  • Incidentally, even if this worked as you expected, Pile will never pop a null. Thus repeated calls to InvokeAndPop() would just keep checking a null reference without changing anything. Probably a bug. Commented Oct 12, 2016 at 14:48

2 Answers 2

1

I find your code not very well-designed... Setting local variable to NULL will not make anyone expect any changes in some other classes internal data. It will definitely lead to bugs sooner or later even if you could achieved this.

It would be better to just use a List<DlgtVoidVoid> instead of array in the Pile class. And instead of nulling the delegate reference, you better create a special method "Remove" which will subsequently call corresponding method of the List.

public class Pile { private List<DlgtVoidVoid> thepile = new List<DlgtVoidVoid>(); public void PushItem(DlgtVoidVoid item) { thepile.Add(item); } public DlgtVoidVoid PeekItem() { return thepile[thepile.Count-1]; } public DlgtVoidVoid PopItem() { var item = thepile[thepile.Count-1]; thepile.RemoveAt(thepile.Count-1); return item; } public void InvokeAndPop() { PopItem()(); } public void Remove(DlgtVoidVoid deletageToRemove) { thepile.Remove(deletageToRemove); } } //... public void Main() { _delvar1 = voidmethod1; _delvar2 = voidmethod2; pileStack.PushItem(ref _delvar1); pileStack.PushItem(ref _delvar2); //trying to invalidate the first delegate handler pileStack.Remove(_delvar1); pileStack.InvokeAndPop();//invoke 2 pileStack.InvokeAndPop();//Now it will throw you IndexOutOfRange exception. You could handle it better inside of the Pile methods } 
Sign up to request clarification or add additional context in comments.

1 Comment

clean and simple and also I haven't to change much of what aready had - thank you for your time
0

Passing by reference is pretty much the same as C++, meaning you can modify the variable value in the caller. But just like in C++ you still couldn't change the value later unless you stored a pointer to pointer.

In your code you are storing the object, not a reference to the variable so you have to call a removal method to actually remove the value from your array. Editing a variable does nothing for any other reference to that object.

You could of course have an object that contains this delegate. Then if you modify that outer object the inner delegate in the stack also becomes null, but it adds another layer of indirection and is messier than just calling a removal method.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.