views:

61

answers:

2

Hi,

The following code seems to execute the FileRetrieved event more than once. I thought delegates were a reference type. I was expecting this to execute once. I'm going to take a guess and say that the reference is being passed by value, therefore copied but I don't like guesswork :-)

public delegate void DirListEvent<T>(T dirItem);

void Main()
{
    DirListEvent<string> printFilename = s => {
        Console.WriteLine (s);
    };

    var obj = new DirectoryLister();

    obj.FileRetrieved += printFilename;
    obj.FileRetrieved += printFilename;

    obj.GetDirListing();
}

public class DirectoryLister {

    public event DirListEvent<string> FileRetrieved;


    public DirectoryLister() {
        FileRetrieved += delegate {};
    }

    public void GetDirListing() {

        foreach (var file in Directory.GetFiles(@"C:\"))
        {
            FileRetrieved(file);
        }
    }
}
+3  A: 

Effectively, FileRetrieved is a collection of delegates, and the same delegate can appear in this collection multiple times. Not all collections are sets ...

reinierpost
Correct, `obj.FileRetrieved` ends up containing multiple references to the same delegate.
Henk Holterman
A: 

Basically, every delegate instance comes with an invocation list, which is essentially just a list of all the references to the target events that you associate with. For instance,

public event DirListEvent<string> FileRetrieved;

the code above creates a delegate type called FileRetrieved (as you already know). This delegate type now has an invocation list that keeps all the delegate instances that you register using += operator or Delegate.Combine method.

obj.FileRetrieved += printFilename;
obj.FileRetrieved += printFilename;

This code basically adds 2 of the same delegate instances to the FileRetrieved invocation list. The invocation list allows duplicate instances. Hence, when FileRetrieved is invoked, it goes through its invocation list and finds that there are 2 methods added (both printFilename) and just delegate the calls to printFilename as it supposed to do.

Try having another line of obj.FileRetrieved += printFilename; and FileRetrieved should invoke printFilename 3 times.

codingbear