It seems that they do if they reference members of the declaring type. This makes perfect sense now that I think about it, but I didn’t think about it earlier and wrote some code that caused a memory leak. I had an object acting as a singleton and referencing a delegate instance that was created from an object acting as a non singleton. Bam! Memory Leak.
I setup a little test to demonstrate. Here is a class that has two methods which return delegate instances:
public class TestSource { private string internalValue = "test"; public Func<bool> GetFunc1() { return () => 1 == 1; } public Func<string> GetFunc2() { return () => internalValue; } }
Notice that GetFunc1() doesn’t have any references to internal members, but GetFunc2() does. Here’s the test class:
class Program { static void Main(string[] args) { // hold no references to TestSource TestFuncInstance(new TestSource().GetFunc1()); TestFuncInstance(new TestSource().GetFunc2()); Console.WriteLine("Press Enter to continue."); Console.ReadLine(); } private static void TestFuncInstance(Delegate func) { Thread.Sleep(1000);// give some time for GC Console.WriteLine(string.Format("Method: {0}",func.Method)); Console.WriteLine(string.Format("DeclaringType: {0}", func.Method.DeclaringType)); Console.WriteLine(string.Format("Target: {0}", func.Target ?? "null")); Console.WriteLine(); } }
This creates two separate instances of TestSource and passes the result of the two GetFunc methods to a test method. Notice that there are no declared variable references to the TestSource object. Here’s the output of the test:
Method: Boolean <GetFunc1>b__0() DeclaringType: TestingDelegates.TestSource Target: null Method: System.String <GetFunc2>b__2() DeclaringType: TestingDelegates.TestSource Target: TestingDelegates.TestSource Press Enter to continue.
I know this test isn’t very scientific, but you’ll see that Func1′s target is null while Func2′s target is not. Func2 has to hold a reference to the declaring object so that it can do it’s job when invoked. Func1 does not need a reference, and seems to free up the declaring object to be garbage collected. This is definitely something to keep in mind when passing around delegates.
Post Footer automatically generated by Add Post Footer Plugin for wordpress.

Hmmm…I think this has something to do with Closures.
I _believe_ that if you look at your code in Reflector you’d see that the anonymous delegate actually becomes a method on an inner class of your declaring type. This would make sense then that the declaring class is not GC’d.
One side note, I think the test would be more explicit if you forced a GC instead of doing a Thread.Sleep(). My $0.02.
It’s not actually a memory leak. It’s because the lambda returned from GetFunc2 refers to a field of the outer object. That field then needs to be lifted (see: lambda lifting).
When this happens, it’s as if a LineItem object was given an implicit reference to its Order object and then the LineItem got passed somewhere else.
As long as you have an uncollected instance of the lambda (which is a closure) that refers to data from outside it’s own scope (the instance filed), that outer scope is kept alive so that the lambda can continue to have access to its lifted data.