Ser*_*694 7 .net c# cil visual-studio c#-7.0
因此,我在使用UWP应用程序时经常使用的模式是使用SemaphoreSlim实例来避免竞争条件(我不喜欢使用lock它,因为它需要一个额外的目标对象,并且它不会异步锁定).
一个典型的代码片段如下所示:
private readonly SemaphoreSlim Semaphore = new SemaphoreSlim(1);
public async Task FooAsync()
{
await Semaphore.WaitAsync();
// Do stuff here
Semaphore.Release();
}
Run Code Online (Sandbox Code Playgroud)
随着更多的try/finally围绕整个事情块,如果之间的代码可能崩溃,但我想保持信号灯工作正常.
为了减少样板,我尝试编写一个包装类,它具有相同的行为(包括try/finally位),所需的代码更少.我也不想使用a delegate,因为每次都会创建一个对象,我只是想减少我的代码而不改变它的工作方式.
我想出了这个课程(为简洁起见,删除了评论):
public sealed class AsyncMutex
{
private readonly SemaphoreSlim Semaphore = new SemaphoreSlim(1);
public async Task<IDisposable> Lock()
{
await Semaphore.WaitAsync().ConfigureAwait(false);
return new _Lock(Semaphore);
}
private sealed class _Lock : IDisposable
{
private readonly SemaphoreSlim Semaphore;
public _Lock(SemaphoreSlim semaphore) => Semaphore = semaphore;
void IDisposable.Dispose() => Semaphore.Release();
}
}
Run Code Online (Sandbox Code Playgroud)
它的工作方式是通过使用它你只需要以下内容:
private readonly AsyncMutex Mutex = new AsyncMutex();
public async Task FooAsync()
{
using (_ = await Mutex.Lock())
{
// Do stuff here
}
}
Run Code Online (Sandbox Code Playgroud)
一条线更短,try/finally内置(using块),真棒.
现在,尽管使用了discard运算符,但我不知道为什么会这样.
丢弃_实际上只是出于好奇,因为我知道我应该写的var _,因为我需要IDisposable在using块的末尾使用该对象,而不是丢弃.
但令我惊讶的是,两种方法都生成了相同的IL:
.method public hidebysig instance void T1() cil managed
{
.maxstack 1
.locals init (
[0] class System.Threading.Tasks.AsyncMutex mutex,
[1] class System.IDisposable V_1
)
IL_0001: newobj instance void System.Threading.Tasks.AsyncMutex::.ctor()
IL_0006: stloc.0 // mutex
IL_0007: ldloc.0 // mutex
IL_0008: callvirt instance class System.Threading.Tasks.Task`1<class System.IDisposable> System.Threading.Tasks.AsyncMutex::Lock()
IL_000d: callvirt instance !0/*class System.IDisposable*/ class System.Threading.Tasks.Task`1<class System.IDisposable>::get_Result()
IL_0012: stloc.1 // V_1
.try
{
// Do stuff here..
IL_0025: leave.s IL_0032
}
finally
{
IL_0027: ldloc.1 // V_1
IL_0028: brfalse.s IL_0031
IL_002a: ldloc.1 // V_1
IL_002b: callvirt instance void System.IDisposable::Dispose()
IL_0031: endfinally
}
IL_0032: ret
}
Run Code Online (Sandbox Code Playgroud)
"discarder" IDisposable存储在现场V_1并正确处理.
那么,为什么会这样呢?该文档不说与使用有关的丢弃操作什么using块,他们只是说,丢弃分配完全被忽略.
谢谢!
该using语句不需要显式声明局部变量.表达式也是允许的.
语言规范指定以下语法.
Run Code Online (Sandbox Code Playgroud)using_statement : 'using' '(' resource_acquisition ')' embedded_statement ; resource_acquisition : local_variable_declaration | expression ;如果resource_acquisition的形式是local_variable_declaration,则local_variable_declaration的类型必须是动态的或可以隐式转换为的类型
System.IDisposable.如果resource_acquisition的形式是表达式,则此表达式必须可隐式转换为System.IDisposable.
分配现有变量(或丢弃结果)也是一种表达方式.例如,以下代码编译:
var a = (_ = 10);
Run Code Online (Sandbox Code Playgroud)
丢弃功能的使用在这里真的是一个红鲱鱼。这样做的原因是因为该using语句可以接受解析为要处理的值的表达式(除了声明变量的替代语法)。此外,赋值运算符解析为分配的值。
您在赋值运算符右侧提供的值是您的 Lock 对象,因此这就是表达式的_ = await Mutex.Lock()解析结果。由于该值(不是作为变量声明,而是作为独立值)是一次性的,因此它将在using.
| 归档时间: |
|
| 查看次数: |
577 次 |
| 最近记录: |