I still don't quite understand what a closure is so I posted these two examples and I want to know whether these examples are both closures or not?
Example A:
List<DirectoryInfo> subFolders = new开发者_如何转开发 List<DirectoryInfo>();
Action<string> FilterSubFoldersStartA =
s => subFolders.
AddRange((new DirectoryInfo(s)).GetDirectories().
Where(d => d.Name.StartsWith("A")));
FilterSubFoldersStartA(@"c:\tempa");
FilterSubFoldersStartA(@"c:\tempb");
Example B:
List<DirectoryInfo> subFolders = new List<DirectoryInfo>();
string filter = "A";
Action<string> FilterSubFoldersStartGen =
s => subFolders.
AddRange((new DirectoryInfo(s)).GetDirectories().
Where(d => d.Name.StartsWith(filter)));
FilterSubFoldersStartGen(@"c:\tempa");
filter = "B";
FilterSubFoldersStartGen(@"c:\tempb");
Your second example makes use of closures (technically you could say that the compiler computes a closure in both cases, but you don't make use of it in the first case).
A closure is simply "all the variables visible to this function". Nothing more, nothing less. And obviously, in both cases, those variables exist, and are determined by the compiler.
But what we usually mean when we talk about "using closures" is that lambda expressions can use all local variables visible at the place they're declared. They're all part of its closure.
In your case, d
is simply the parameter to the lambda function, and since that's all you use in the first case, you're not really taking advantage of closures.
In the second case, filter
is not defined in the lambda expression, it's not a parameter or anything. It's a local variable which just so happens to be visible at the place where the lambda is declared. So it is part of the lambda's closure, which allows you to reference it in the body of the lambda.
Edit
As pointed out in the comments, I didn't read your code too closely. I only noticed the second lambda expression in each example. The first lambda does use closures (it closes over subFolders
in both cases.)
Yea, a closure is nothing more than a function that "saves" some variables from the environment in which it is defined. So in both of your examples, the defined action saves the list named subFolders
, which can be referenced by the functions even after the local variable is out of scope. The filter
variable in the second example is also saved by the defined function.
A more precise definition here
Both examples have closures. In "A" anonymous method captures local variable subFolders. In "B" anonymous method captures local variables subFolders and filter. Also take a look here.
P.S. Also note that you are actually using closure in "A" because you are using subFolders variable.
Here's an example from http://www.agileatwork.com/a-proper-closure-in-csharp/ of something that might look a little more familiar if you're comfortable with JavaScript. A closure is created around the tax
variable so the calculation is only done one time. It isn't exactly easy on the eyes, but it's cool that you can do this type of thing in C#.
public class Order
{
public Order(ITaxCalculator taxCalculator)
{
CalculateTax = new Func<Func<decimal>>(() =>
{
decimal? tax = null;
return () =>
{
if (!tax.HasValue)
{
tax = taxCalculator.Calculate(this);
}
return tax.Value;
};
})();
}
public Func<decimal> CalculateTax { get; set; }
...
}
精彩评论