views:

75

answers:

2

When adding to a list, if I add the property of a class instance, is it set to a reference of the property's value or a reference to the property?

Example:

If I have:

class A {
     public Action<Guid> SomeDelegate { get; set; }
}

And in a different class I create an instance of class A, ie:

class B {
     public B() {
          a = new A();
          a.SomeDelegate = someFunction;
          List<Action<Guid>> myList = new List<Action<Guid>>;
          myList.Add(a.SomeDelegate);
          a.SomeDelegate = anotherFunction;
      }
}

What will be in myList? A reference to anotherFunction or a reference to someFunction?

If it is a reference to someFunction, how would I go about making it a reference to anotherFunction?

Thanks!

+4  A: 

The single item in your list will be a reference to someFunction.

Think of like this:

You have an instance of A. Now A has a property called SomeDelegate. You have a references someFunction and anotherFunction to delegates that I will also call someFunction and anotherFunction respectively in the pictures below. So the picture is this:

a local to B constructor
---------------
|             |
|SomeDelegate-----------> someFunction
|             |           anotherFunction
---------------

Now you add a.SomeDelegate to myList. So the picture is this:

a local to B constructor
---------------
|             |
|SomeDelegate-----------> someFunction <-------myList[0]
|             |           anotherFunction
---------------

Now you come along and change SomeDelegate to refer to anotherFunction. Now the picture is this:

a local to B constructor
---------------
|             |
|SomeDelegate-----|       someFunction <-------myList[0]
|             |   |-----> anotherFunction
---------------

This should make it clear that myList[0] still refers to someFunction and why.

Now, if you want myList to see the changes, the best easiest way is to make it a list of A.

 A a = new A();
 a.SomeDelegate = someFunction;
 List<A> myList = new List<A>();
 myList.Add(a);
 a.SomeDelegate = anotherFunction;

Now it will be the case that myList[0].SomeDelegate refers to anotherFunction. You can easily extract the actions like so:

 var actions = myList.Select(x => x.SomeDelegate).ToList();
Jason
+1  A: 

I believe the List would continue to hold a reference to a delegate instance pointing to SomeFunction.

The low-tech solution to achieving what you want to achieve would be to wrap the delegate inside another object. Add this object to the list; you are then free to mutate the wrapper object, change its property to the new value.
At the point where you consume the delegates in the list, instead of directly invoking the delegate, use wrapperInstance.Delegate(params)

Update: I think my response wasn't clear from Jason's comment.

class B
    {
        List<A> myList;
        public B() {
          var a = new A();
          a.SomeDelegate = ( x => Console.WriteLine("SomeFunction " + x) );
          myList = new List<A>();
          myList.Add(a);               // add wrapper object instead of delegate to list
            SerialInvokeDelegates();   // will invoke SomeFunction

          a.SomeDelegate = (x => Console.WriteLine("AnotherFunction " + x));
            SerialInvokeDelegates();   // will invoke AnotherFunction
        }

        private void SerialInvokeDelegates()
        {
            Console.WriteLine("Invoking all delegates in B's List");
            foreach (var a in myList)
                a.SomeDelegate(Guid.NewGuid());
        }
    }
Gishu
The class `A` is already a wrapper around the delegate. Just use that.
Jason