Захватывает ли лямбда самый внешний экземпляр? ⇐ C#
-
Anonymous
Захватывает ли лямбда самый внешний экземпляр?
Когда я раскомментирую await Task.Delay(1_000);, foo.DoAsync внутри Task.Run — это Task.CompletedTask, потому что он ожидает служебных данных Task.Run. Поэтому он работает нормально.
Когда я комментирую await Task.Delay(1_000);, foo.DoAsync внутри Task.Run — это сам собой. После первого попадания в точку останова2 в режиме отладки точка останова2 больше не попадает.
internal class Foo
{
public Task DoAsync { get; set; }
public void Recursive()
{
// Breakpoint1
Recursive();
}
}
var foo = new Foo() { DoAsync = Task.CompletedTask };
//foo.Recursive();
Console.WriteLine($"Outer ThreadId: {Environment.CurrentManagedThreadId}");
var task = Task.Run(async () =>
{
Console.WriteLine($"Inner ThreadId: {Environment.CurrentManagedThreadId}");
// Breakpoint2
await foo.DoAsync;
Console.WriteLine("""
******
******
******
done
******
******
******
""");
});
await Task.Delay(1_000);
foo.DoAsync = task;
await foo.DoAsync;
Я ожидал, что он будет бесконечно достигать точки останова 2, поскольку foo.Recursive будет бесконечно достигать точки останова 1, пока не произойдет сбой. Куда направляется поток управления после первоначального попадания в точку останова 2?
Извините за путаницу.
Когда мне нужно что-то сделать test Я просто пишу foo, bar, baz, комментирую по завершении
, пишу новый foo, копирую какой-то метод из предыдущего и так далее.
Я лечил foo.DoAsync как Func хотя сейчас это Task.
Поэтому, когда мои глаза увидели await foo.DoAsync,
мой мозг интерпретировал это как await foo.DoAsync()< /code>
Могу ли я задать еще один вопрос, если можно.
Захватывает ли лямбда самый внешний экземпляр?
Спасибо за предыдущий ответьте, кстати.
public static async Task ActualAsync()
{
var foo = new Foo();
Console.WriteLine("************** Actual begin **************");
var task = Task.Run(async () =>
{
// Causes a deadlock because lambda didn't caputer the foo.ATask before it's overwritten.
Console.WriteLine($"a: {await foo.ATask} expecting 1");
Console.WriteLine($"b: {await foo.BTask} expecting 2");
return 3;
});
// Give time to Task.Run so it can run before foo.ATask is overwritten.
//await Task.Delay(1000);
foo.ATask = task;
await foo.ATask;
Console.WriteLine("************** Actual end **************");
}
internal class Foo
{
public Task ATask = Task.FromResult(1);
public Task BTask = Task.FromResult(2);
}
Я думал, что лямбда будет захватывать переменные отдельно.
public static async Task ExpectedAsync()
{
var foo = new Foo();
var lambdaInstance = new FooLambdaExpected()
{
ATask = foo.ATask,
BTask = foo.BTask
};
Console.WriteLine("************** Expected begin ************");
var task = Task.Run(lambdaInstance.LambdaMethod);
foo.ATask = task;
await foo.ATask;
Console.WriteLine("************** Expected end ************");
}
internal class FooLambdaExpected
{
public Task ATask { get; set; } = null!;
public Task BTask { get; set; } = null!;
public async Task LambdaMethod()
{
Console.WriteLine($"a: {await ATask} expecting 1");
Console.WriteLine($"b: {await BTask} expecting 2");
return 3;
}
}
и я думаю, он сам ловит foo.
public static async Task AssumedAsync()
{
var foo = new Foo();
var lambdaInstance = new FooLambdaAssumed()
{
Foo = foo
};
Console.WriteLine("************** Assumed begin ***********");
var task = Task.Run(lambdaInstance.LambdaMethod);
// Give time to Task.Run so it can run before foo.ATask is overwritten.
//await Task.Delay(1000);
foo.ATask = task;
await foo.ATask;
Console.WriteLine("************** Assumed end ***********");
}
internal class FooLambdaAssumed
{
public Foo Foo { get; set; } = null!;
public async Task LambdaMethod()
{
Console.WriteLine($"a: {await Foo.ATask} expecting 1");
Console.WriteLine($"b: {await Foo.BTask} expecting 2");
return 3;
}
}
Подробнее здесь: https://stackoverflow.com/questions/792 ... t-instance
Когда я раскомментирую await Task.Delay(1_000);, foo.DoAsync внутри Task.Run — это Task.CompletedTask, потому что он ожидает служебных данных Task.Run. Поэтому он работает нормально.
Когда я комментирую await Task.Delay(1_000);, foo.DoAsync внутри Task.Run — это сам собой. После первого попадания в точку останова2 в режиме отладки точка останова2 больше не попадает.
internal class Foo
{
public Task DoAsync { get; set; }
public void Recursive()
{
// Breakpoint1
Recursive();
}
}
var foo = new Foo() { DoAsync = Task.CompletedTask };
//foo.Recursive();
Console.WriteLine($"Outer ThreadId: {Environment.CurrentManagedThreadId}");
var task = Task.Run(async () =>
{
Console.WriteLine($"Inner ThreadId: {Environment.CurrentManagedThreadId}");
// Breakpoint2
await foo.DoAsync;
Console.WriteLine("""
******
******
******
done
******
******
******
""");
});
await Task.Delay(1_000);
foo.DoAsync = task;
await foo.DoAsync;
Я ожидал, что он будет бесконечно достигать точки останова 2, поскольку foo.Recursive будет бесконечно достигать точки останова 1, пока не произойдет сбой. Куда направляется поток управления после первоначального попадания в точку останова 2?
Извините за путаницу.
Когда мне нужно что-то сделать test Я просто пишу foo, bar, baz, комментирую по завершении
, пишу новый foo, копирую какой-то метод из предыдущего и так далее.
Я лечил foo.DoAsync как Func хотя сейчас это Task.
Поэтому, когда мои глаза увидели await foo.DoAsync,
мой мозг интерпретировал это как await foo.DoAsync()< /code>
Могу ли я задать еще один вопрос, если можно.
Захватывает ли лямбда самый внешний экземпляр?
Спасибо за предыдущий ответьте, кстати.
public static async Task ActualAsync()
{
var foo = new Foo();
Console.WriteLine("************** Actual begin **************");
var task = Task.Run(async () =>
{
// Causes a deadlock because lambda didn't caputer the foo.ATask before it's overwritten.
Console.WriteLine($"a: {await foo.ATask} expecting 1");
Console.WriteLine($"b: {await foo.BTask} expecting 2");
return 3;
});
// Give time to Task.Run so it can run before foo.ATask is overwritten.
//await Task.Delay(1000);
foo.ATask = task;
await foo.ATask;
Console.WriteLine("************** Actual end **************");
}
internal class Foo
{
public Task ATask = Task.FromResult(1);
public Task BTask = Task.FromResult(2);
}
Я думал, что лямбда будет захватывать переменные отдельно.
public static async Task ExpectedAsync()
{
var foo = new Foo();
var lambdaInstance = new FooLambdaExpected()
{
ATask = foo.ATask,
BTask = foo.BTask
};
Console.WriteLine("************** Expected begin ************");
var task = Task.Run(lambdaInstance.LambdaMethod);
foo.ATask = task;
await foo.ATask;
Console.WriteLine("************** Expected end ************");
}
internal class FooLambdaExpected
{
public Task ATask { get; set; } = null!;
public Task BTask { get; set; } = null!;
public async Task LambdaMethod()
{
Console.WriteLine($"a: {await ATask} expecting 1");
Console.WriteLine($"b: {await BTask} expecting 2");
return 3;
}
}
и я думаю, он сам ловит foo.
public static async Task AssumedAsync()
{
var foo = new Foo();
var lambdaInstance = new FooLambdaAssumed()
{
Foo = foo
};
Console.WriteLine("************** Assumed begin ***********");
var task = Task.Run(lambdaInstance.LambdaMethod);
// Give time to Task.Run so it can run before foo.ATask is overwritten.
//await Task.Delay(1000);
foo.ATask = task;
await foo.ATask;
Console.WriteLine("************** Assumed end ***********");
}
internal class FooLambdaAssumed
{
public Foo Foo { get; set; } = null!;
public async Task LambdaMethod()
{
Console.WriteLine($"a: {await Foo.ATask} expecting 1");
Console.WriteLine($"b: {await Foo.BTask} expecting 2");
return 3;
}
}
Подробнее здесь: https://stackoverflow.com/questions/792 ... t-instance
Мобильная версия