Можно ждать Task.WhenAll (t1, & hellip ;, tn), когда ti получается из того же типа? [Дубликат]

Есть ли способ вернуть ссылку из функции без аргументов?

blockquote>

Нет (кроме ссылок на статические значения, но здесь это не полезно).

Однако вы можете посмотреть OpenOptions::create . Если вы измените свою первую строку в main на

let  f = OpenOptions::new().write(true).create(true).open(b"foo.txt");

, файл будет создан, если он еще не существует, что должно решить вашу исходную проблему.

12
задан Nael 14 June 2016 в 18:42
поделиться

2 ответа

C # не допускает отклонения от классов, только интерфейсы и делегаты, которые параметризуются ссылочными типами. Task<T> является классом.

Это несколько неудачно, так как Task<T> является одним из тех редких классов, которые могли [2] сделать безопасным ковариантным.

Однако достаточно легко преобразовать Task<Derived> в Task<Base>. Просто создайте вспомогательный метод / лямбда, который берет Task<Derived> и возвращает Task<Base>, ждет переданную задачу и возвращает значение, отличное от Base. Компилятор C # позаботится об остальном. Конечно, вы теряете ссылочную идентификацию, но вы никогда не узнаете это с классом.

20
ответ дан Eric Lippert 18 August 2018 в 17:08
поделиться

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

Task<TBase> GeneralizeTask<TBase, TDerived>(Task<TDerived> task) 
    where TDerived : TBase 
{
    var newTask = new Task<TBase>(() => {
        if (task.Status == TaskStatus.Created) task.Start();
        task.Wait();
        return (TBase)task.Result;
    });
    return newTask;
}

Edit:

Как указывает @EricLippert, это может быть значительно упрощено. Сначала я попытался найти такой способ реализации этого метода, но не смог найти тот, который был скомпилирован. Как оказалось, реальное решение было еще проще, чем я себе представлял.

async Task<TBase> GeneralizeTask<TBase, TDerived>(Task<TDerived> task) 
    where TDerived : TBase 
{
    return (TBase) await task;
}

Затем вы можете вызвать Bar() следующим образом.

Bar(m => GeneralizeTask<IResult, Result>(DoSomething((Message)m)));
1
ответ дан recursive 18 August 2018 в 17:08
поделиться
  • 1
    Это бесполезно выделяет поток пула потоков, чтобы синхронно сидеть там, ожидая завершения сложной задачи, вы также возвращаете неармированную задачу, поэтому она никогда не закончится (именно поэтому вы не должны использовать Task конструктор вообще, когда-либо), вы также неправильно обрабатываете случаи ошибок / аннулирования для сложенной задачи. – Servy 14 June 2016 в 20:11
  • 2
    Есть ли причина, почему вы не просто используете await? Похоже, async Task<B> Cast<B, D>(Task<D> t) where D : B => (B) await t; намного проще. – Eric Lippert 14 June 2016 в 22:19
  • 3
    @EricLippert: Это довольно четкое решение. Я попытался использовать ожидание, но не мог понять, как его написать. Все мои попытки дали не компилируемый код с ошибками, как CS4010 Cannot convert async lambda expression to delegate type 'Func<TBase>'. An async lambda expression may return void, Task or Task<T>, none of which are convertible to 'Func<TBase>'.. По-видимому, я не понимаю задачи, как я и думал. – recursive 15 June 2016 в 00:02
  • 4
    Я думаю, вы хотели сказать Func<Task<TBase>> Что такое лямбда? функция. Что возвращает асинхронная функция? Задача. Какую ценность делает эта задача? ТБаза. Так что это функция задачи tbase. – Eric Lippert 15 June 2016 в 16:36
Другие вопросы по тегам:

Похожие вопросы: