使用带有use
的通配符模式在序列表达式中起作用,但不是这样。有这个原因吗?
let mkDisposable() =
{ new IDisposable with
member __.Dispose() = () }
let mkSeq() =
seq {
use _ = mkDisposable() //OK
()
}
let f() =
use _ = mkDisposable() //ERROR: 'use' bindings must be of the form 'use <var> = <expr>'
()
答案 0 :(得分:2)
我认为这是计算表达式(在这种情况下是一个序列表达式,但这种行为适用于所有计算表达式)的自然(但意外)后果。 As the spec indicates,
use pat = expr
cexpr
被翻译为
Using(expr, fun pat -> cepxr)
因为这是一个浅层的句法翻译,你可以使用编写函数时可以使用的任何模式,包括_
。但是,对于正常use
绑定,绑定的左侧必须是标识符,而不是模式(请参阅section 6.6.3 of the spec)。< / p>
答案 1 :(得分:1)
我已经做了一些挖掘,似乎处理特殊方式seq
表达式会改变use
的规则。 seq
表达式实际上已转换为以下IDisposable
字段,该字段在序列完成时处理。
internal sealed class mkSeq@11<a> : GeneratedSequenceBase<a>
{
[DebuggerBrowsable(DebuggerBrowsableState.Never), CompilerGenerated, DebuggerNonUserCode]
public IDisposable matchValue = matchValue;
[DebuggerBrowsable(DebuggerBrowsableState.Never), CompilerGenerated, DebuggerNonUserCode]
public int pc = pc;
[DebuggerBrowsable(DebuggerBrowsableState.Never), CompilerGenerated, DebuggerNonUserCode]
public a current = current;
public mkSeq@11(IDisposable matchValue, int pc, a current)
{
}
public override int GenerateNext(ref IEnumerable<a> next)
{
switch (this.pc)
{
case 2:
{
break;
}
case 3:
{
goto IL_55;
}
default:
{
this.matchValue = Program.mkDisposable();
this.pc = 2;
break;
}
}
this.pc = 3;
LanguagePrimitives.IntrinsicFunctions.Dispose<IDisposable>(this.matchValue);
this.matchValue = null;
this.pc = 3;
IL_55:
this.current = default(a);
return 0;
}
public override void Close()
{
switch (this.pc)
{
case 1:
{
goto IL_41;
}
case 3:
{
goto IL_41;
}
}
this.pc = 3;
LanguagePrimitives.IntrinsicFunctions.Dispose<IDisposable>(this.matchValue);
IL_41:
this.pc = 3;
this.current = default(a);
}
public override bool get_CheckClose()
{
switch (this.pc)
{
case 1:
{
return false;
}
case 3:
{
return false;
}
}
return true;
}
[CompilerGenerated, DebuggerNonUserCode]
public override a get_LastGenerated()
{
return this.current;
}
[CompilerGenerated, DebuggerNonUserCode]
public override IEnumerator<a> GetFreshEnumerator()
{
return new Program<a>.mkSeq@11(null, 0, default(a));
}
}
通常use
转换为:
IDisposable e = Program.mkDisposable();
try
{
}
finally
{
IDisposable disposable = e as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
如果没有变量名,编译器将忽略表达式的结果,因此无法处理它。说实话,似乎应该为use
做一个特殊情况,所以所有样板都是在幕后创建的,就像我们在seq
表达式中看到的那样。