Captured variable instantiating problem

2019-08-14 13:45发布

I'm currently musing about some idea I can't get right.

The problem is that I want to use one lambda function to instantiate a captured variable and another lambda to access a property of that variable.

Since the instantiating happens within the lambda the variable isn't actually instantiated the time I want to use it within the second lambda.. this is kind of a chicken and egg problem.

I know that the variable will be instantiated the time it's used in the second lambda but the compiler doesn't.

Is there any way my idea could work? Here's the actual code:

class Program
{
    static void Main(string[] args)
    {
        SqlCommand cmd;

        using (new DisposableComposite(
            () => cmd = new SqlCommand(),
            () => cmd.Connection)) // <- compiler error - variable not instantiated
        {
            // code
        }
    }
}

class DisposableComposite : IDisposable
{
    private List<IDisposable> _disposables = new List<IDisposable>();

    public DisposableComposite(params Func<IDisposable>[] disposableFuncs)
    {
        // ensure the code is actually executed
        foreach (var func in disposableFuncs)
        {
            IDisposable obj = func.Invoke();
            _disposables.Add(obj);
        }
    }

    public void Dispose()
    {
        foreach (var disposable in _disposables)
        {
            disposable.Dispose();
        }
    }
}

3条回答
够拽才男人
2楼-- · 2019-08-14 14:17

Do you mean just adding:

SqlCommand cmd = null;

(which solves the "definite assignment" glitch; it is definitely assigned... a null ;-p We then update the value before it is used).

IMO, though, you'd do better with nested using statements... and it isn't clear (from the code) where the actual connection is going to come from...

using(var conn = new SqlConnection(...))
using(var cmd = conn.CreateCommand()) {
    // ...
}
查看更多
我命由我不由天
3楼-- · 2019-08-14 14:26

You can only avoid this by setting cmd to null before the using block:

    SqlCommand cmd=null;

    using (new DisposableComposite(
        () => cmd = new SqlCommand(),
        () => cmd.Connection)) // <- compiler error - variable not instantiated
    {
        // code
    }
查看更多
Evening l夕情丶
4楼-- · 2019-08-14 14:29

Agree with Marc that this does not really feel right.

Another option would be to define a new Context type object, that on Dispose disposes all the objects it provides.

Eg.

using (var ctx = GetContext()) {
   var cmd = ctx.CreateCommand();
   cmd.Connection = ctx.CreateConnection();
}
// cmd is Disposed 
// cmd.Connection is Disposed 
查看更多
登录 后发表回答