次の方法で共有


Don't mix using statements and lambda expressions

Title pretty much says it all but what good is a rule without any explanation.  The main issue here is that at the core, using statements and lambda expressions both alter variable lifetimes.  Unfortunately they alter the lifetime in different directions.  Using will shorten the life time of a variable to the specified block.  This is a somewhat artificial way because the object is still technically alive but can't be trusted to do anything.  Lambda expressions take a variable limited to a specific scope and extends their lifetime to potentially be that of a heap value. Anytime two features alter the attribute of a variable in different directions, they can probably cause problems when used in conjunction. 

Take the following contrived but real example. 

         static Future<int> Example() {
            using (var obj = new MyDisosableObject()) {
                return Future.Create(() => obj.SomeFunction());
            }
        }

Comments

  • Anonymous
    July 16, 2008
    PingBack from http://blog.a-foton.ru/2008/07/dont-mix-using-statements-and-lambda-expressions/

  • Anonymous
    July 16, 2008
    Lambda expressions are really cool, but they present some interesting problems because they aren't really

  • Anonymous
    July 16, 2008
    Never would have thought of that one...Thanks.

  • Anonymous
    July 16, 2008
    The program does what you say it should to. It looks like the programmer clearly does not understand when is what executed. By simply moving the using statement inside the delegate it will be fixed...

  • Anonymous
    July 17, 2008
    You need to clarify your blanket rule. It is perfectly fine to use lambdas inside a using block. I believe what you meant to say is: Don’t take any lifetime dependencies upon the object being 'used', and return that object as a lifted variable in a lambda function.   Below is a contrived but perfectly valid example of a lambda inside a using. static void Example() {  int[] numbers = { 1, 2, 3, 4, 5 };  using (var obj = new MyDisosableObject()) {    numbers.ForEach(i => Console.WriteLine("{0} squared is {1}", i, i * i));  } }

  • Anonymous
    July 20, 2008
    General Lessons That I Learned From Waegis : Keyvan Nayyeri shares the lessons he learned from launching Waegis , a spam filter for web sites. Don't Mix Using Statements And Lambda Expressions : Jared Parsons explains why you do not want to mix using

  • Anonymous
    July 22, 2008
    The comment has been removed

  • Anonymous
    July 22, 2008
    Ok, I do agree with the above. I had to go back and revalidate my Synchronized<T> as you made me think, (which is the point of this right?) as I do both of the above, but not at the same time.

  • Anonymous
    July 22, 2008
    Lambda expressions appear to be just syntactic sugar apart from querying a SQL server database.

  • Anonymous
    August 11, 2008
    Jared I must say this is strange behavior. Shouldn't the using statement be able to override the scope extension of the lambda expression instead of allowing this inconsistent behavior?

  • Anonymous
    August 11, 2008
    @Orlando, I think you mean issue a compiler error because of the scope change.  If so in an ideal world this should be the case.  However it is not done at this time for a couple of reasons. The first is cost.  For the compiler to accurately spot this as an error it must determine that the lambda will actually live beyond the scope of the current function.  This is very expensive (if not impossible).  In this case the compiler would have to dig into the IL of every function the lambda was either passed to or called.  The analysis would include deep flow analysis to determine if the lambda was ever stored in a place that was eventually returned from the function or passed to a different thread or even to PInvoke.  This is very costly in both man hours to implement and compile time.   The other is correctness.  Even though it's against design guidlines, there is nothing stopping you from using an object once it's been disposed.  You can in fact (please don't though) design an object to have a subset of it's properties/methods be valid after it's disposed.  In this case the code I laid out would still be correct so the compiler would be issuing a false warning.  

  • Anonymous
    August 11, 2008
    I think it makes sense to do this: func<IDisposable, string> f = x => { using(x) { x.ToString() } }; This certainly can't be a universally Bad Idea(TM), can it?

  • Anonymous
    August 12, 2008
    The comment has been removed

  • Anonymous
    August 14, 2008
    I think it is the C# version of this C++ code int* dummy( ) {     int d = 0;     return &d; }

  • Anonymous
    February 22, 2009
    General Lessons That I Learned From Waegis : Keyvan Nayyeri shares the lessons he learned from launching Waegis , a spam filter for web sites. Don't Mix Using Statements And Lambda Expressions : Jared Parsons explains why you do not want to mix using