Подстановочный знак «использовать» работает в выражении последовательности, но не иначе - PullRequest
4 голосов
/ 09 декабря 2011

Использование шаблона подстановки с 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>'
  ()

Ответы [ 2 ]

2 голосов
/ 09 декабря 2011

Я полагаю, что это естественное (но неожиданное) последствие десагерирования выражений вычислений (в данном случае это выражение последовательности, но это поведение применимо ко всем выражениям вычислений). Как указано в спецификации, ,

use pat = expr
cexpr

переведено на

Using(expr, fun pat -> cepxr)

Поскольку это неглубокий синтаксический перевод, вы можете использовать любой шаблон, который можно использовать, когданаписание функции, в том числе просто _.Однако для нормальных use привязок левая сторона привязки должна быть идентификатор , а не шаблон (см. раздел 6.6.3 спецификации ).

1 голос
/ 09 декабря 2011

Я немного покопался, и кажется, что специальный способ обработки 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...