Reputation: 61
I have a situation where code is behaving differently when compiled on two different development boxes. I can't figure out why. I'm not sure what keywords best describe this issue.
When Rabbit gets called on one box source has the value
{() => Program.Names}
On another box source has the value
{() => value(NPC.Program+<>c__DisplayClass1_0).Names}
Hole always has the value no matter what computer it's compiled on.
{() => value(NPC.Program+<>c__DisplayClass1_0).closure}
I'm trying to figure out why one machine has the expression for the class and the other machine has the value for the closure when calling Rabbit. I'd also like to know if there's a way to control that. Thanks!
class Program
{
public static ObservableCollection<string> Names = new ObservableCollection<string>();
static void Main(string[] args)
{
string closure = "closure";
if(closure.Length > 0)
{
GoingDown(p => {
closure.ToString();
Names = new ObservableCollection<string>();
Rabbit(() => Names);
Hole(() => closure);
}, closure);
}
}
public static void Rabbit<SourceType>(Expression<Func<ObservableCollection<SourceType>>> source)
{
"Testing".ToString();
}
public static void Hole(Expression<Func<object>> source)
{
"Testing".ToString();
}
public static void GoingDown(Action<object> a, object target)
{
Action b = () =>
{
a(target);
};
b();
}
}
Upvotes: 0
Views: 177
Reputation: 660563
First: as the comment indicates, it would be helpful to know which versions of .NET / C# / etc produce which behaviour.
Second: which behaviour, if either, is correct? The specification does not say. It gives a compiler broad latitude to implement lambdas as delegates and expression trees as it sees fit.
Third: which is better? Plainly there is no need to copy static field Names to a closure class. I would expect the non-closure version to be generated; I suspect that the version which is generating a closure has a bug. Perhaps the bug has been fixed in whatever version does not display the closure semantics.
Fourth: can you control this behaviour? Evidently yes; you have one machine which has the behaviour and one which does not, so you can simply choose to sink the machine that has the bad behaviour to the bottom of the ocean, and use the machine which has the desired behaviour.
Alternatively: there is no requirement that you use the compiler's implementation of lambda semantics. Lambdas are a syntactic sugar; feel free to generate your expression trees "by hand" if you don't like the expression tree the compiler gives you.
Upvotes: 4