Использование (Reactive-) событий в финализаторах - PullRequest
0 голосов
/ 08 октября 2019

У меня есть следующее бизнес-правило: у меня есть лицензия, которую я получаю от другой программы, которая должна использоваться третьей программой. После того, как третья программа подтверждает, что она получила лицензию, я хочу записать ее в файл для целей документации. Если что-то пойдет не так (включая пользователя, закрывающего часть моего приложения, которая ожидает ответа), мне нужно записать лицензию обратно в программу, которая отправляет мне лицензию, чтобы сохранить ее там снова. Мне (в целях безопасности, как мне говорят) не разрешено просто сохранять лицензию (зашифрованную или нет) в файле и вызывать ее через день.

Основной случай, когда другое приложение ожидает подтверждения лицензиипрост:

public bool UseKey(Func<string, bool> func, string serviceTag)
{
    Throw.IfNull(serviceTag, nameof(serviceTag));
    Throw.IfNull(func, nameof(func)); //Check if null

    if (func(_license)) //Programm acknowledged.
    {
        _keyUsed.OnNext(new UsedKey(serviceTag, _license)); //License was used. Therefore inform others that it can be written to file.
        return true;
    }
    return false; //Didn't work. Inform caller.
}

Моя идея для случая, когда что-то пошло не так, была следующая: я реализую интерфейс IDisposable, и в моем методе Dispose (bool) я отправлю правильное событие, информирующееобработчик, чтобы правильно написать обратно.

void Dispose(bool disposing)
{
    if (!_disposed)
    {
        if (disposing)
        {
            if (!_keyWasUsed)
                _keyNotUsed.OnNext(_license);
            _keyUsed.Dispose();
            _keyNotUsed.Dispose();
        }

        // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
        // TODO: set large fields to null.

        _disposed = true;
    }
}

Проблема, которую я вижу, имеет две стороны.

  1. Если клиент не вызывает метод Dispose, я бы не узнал, что что-то пошло не так.
  2. Если я помещу вызов события в финализатор, я не смогуточно знаю, что я могу даже инициировать событие, потому что, возможно, мои ссылки уже очищены или поле лицензии уже собрано.

Поэтому мой вопрос (ы): Как я могу выпустить событие или некоторые другиесообщение (или Rx, или даже классические события, если это что-то облегчает) другому исполняемому коду из финализатора?

(или есть ли лучший подход, чем использование IDisposable для такой работы, чтодает мне гарантию, что либо операция завершится успешно, либо я смогу выполнить откат (вроде транзакций sql)?)

...