c#: Как из асинхронного кода сделать task?

295
12 января 2017, 03:21

Здравствуйте, уважаемые.

Я хочу сделать вот что:

у меня есть код. Он представляет из себя вызов внешней библиотеки и callback из неё.

Я хочу - для дальнейшей работы - сделать из этого task.

(в частности, что бы потом воспользоваться методом .ContinueWith()).

Вот код, который я хочу обернуть в task:

public partial class Form1 : Form {
    public Form15() {
        InitializeComponent();
        button1.Click += button1_Click;
    }
    void button1_Click(object sender, EventArgs e) {
        SevenZipExtractor.SetLibraryPath(@"c:\Program Files\7-Zip\7z.dll");
        SevenZipCompressor compressor = new SevenZipCompressor();
        compressor.ArchiveFormat=OutArchiveFormat.SevenZip;
        compressor.CompressionLevel=CompressionLevel.Ultra;
        compressor.CompressionMode=CompressionMode.Create;
        string[] ffNames = new[] {@"c:\Temp\my.log"};
        compressor.CompressionFinished += compressor_CompressionFinished;
        compressor.CompressFiles(@"c:\Temp\my.log.7z", ffNames);
    }
    void compressor_CompressionFinished(object sender, EventArgs e) {
        MessageBox.Show("Ready!");
    }
}

То есть, в строке

compressor.CompressFiles(@"c:\Temp\my.log.7z", ffNames);

происходит запуск внешнего компонента, в строке

MessageBox.Show("Ready!");

как раз приходит callback, по которому можно завершить задачу

(показывать messageBox она, конечно же, не должна - просто завершаться с приходом коллбэка)

Спасибо за подсказки!

Answer 1

Это описано в документации. Вам нужно использовать TaskCompletionSource.

Для вашего случая:

async Task CompressFilesAsync(
    SevenZipCompressor compressor,
    string archiveName, params string[] fileFullNames)
{
    var tcs = new TaskCompletionSource<int>(); // тип параметра неважен
    EventHandler<EventArgs> handler = null;
    handler = (sender, args) =>
    {
        compressor.CompressionFinished -= handler;
        tcs.TrySetResult(0);
    };
    compressor.CompressionFinished += handler;
    // кажется, это асинхронный метод, в отличие от синхронного CompressFiles
    compressor.BeginCompressFiles(archiveName, DispatcherPriority.Normal, fileFullNames);
    return tcs.Task;
}

Можно ещё сделать из этого extension-метод:

public static class SevenZipCompressorExtensions
{
    public static async Task CompressFilesAsync(
        this SevenZipCompressor compressor,
        string archiveName, params string[] fileFullNames)
    {
        // ...
    }
}

и пользоваться:

SevenZipCompressor compressor = new SevenZipCompressor()
{
    ArchiveFormat = OutArchiveFormat.SevenZip,
    CompressionLevel = CompressionLevel.Ultra,
    CompressionMode = CompressionMode.Create
};
string[] ffNames = new[] { @"c:\Temp\my.log" };
await compressor.CompressFilesAsync(@"c:\Temp\my.log.7z", ffNames);
MessageBox.Show("Ready!");
READ ALSO
Как перетащить файл в консоль

Как перетащить файл в консоль

Хочу сделать считывание модулей ит

289
Разбиение файла на n частей java

Разбиение файла на n частей java

Требуется разбить файл (как правило архив) на определенное количество частейНашел готовый рабочий вариант на c#, но не смог его адаптировать...

1041
Использование фильтра в bindingsource при использовании entity framework

Использование фильтра в bindingsource при использовании entity framework

Здравствуйте, возникли проблемы при фильтрации в bindingSourceНасколько я понимаю, если использовать entity framework, то свойство SupportsFiltering bindingsource принимает...

397
Как грамотно убрать фокус с TextBox?

Как грамотно убрать фокус с TextBox?

Всем доброе утроКак грамотно убрать фокус с TextBox? Свойство Focused для данного контрола доступно только для чтения

909