Невозможно неявно преобразовать тип из задачи ‹›

Я пытаюсь освоить синтаксис асинхронного метода в .NET 4.5. Я думал, что правильно понял примеры, однако, независимо от типа асинхронного метода (т.е. Task<T>), я всегда получаю один и тот же тип ошибки при преобразовании обратно в T, что, как я понял, было в значительной степени автоматическим. Следующий код вызывает ошибку:

Невозможно неявно преобразовать тип "System.Threading.Tasks.Task<System.Collections.Generic.List<int>>" в "System.Collections.Generic.List<int>"

public List<int> TestGetMethod()
{
    return GetIdList(); // compiler error on this line
}


async Task<List<int>> GetIdList()
{
    using (HttpClient proxy = new HttpClient())
    {
        string response = await proxy.GetStringAsync("www.test.com");
        List<int> idList = JsonConvert.DeserializeObject<List<int>>();
        return idList;
    }
}

Это не сработает, если я также явно приведу результат. Этот:

public List<int> TestGetMethod()
{
    return (List<int>)GetIdList();  // compiler error on this line
}

несколько предсказуемо приводит к этой ошибке:

Невозможно преобразовать тип System.Threading.Tasks.Task<System.Collections.Generic.List<int>> в System.Collections.Generic.List<int>

Любая помощь очень ценится.


person PaulR    schedule 14.10.2012    source источник
comment
«Автоматическое разворачивание» задачи от ‹T› до T - это эффект ожидания задачи. Если вы измените TestGetMethod на асинхронный, он может ожидать GetIdList (), чтобы получить T в локальную переменную   -  person James Manning    schedule 15.10.2012
comment
Несвязанный, но по соглашению рекомендуется GetIdListAsync (), хотя, конечно, не имеет большого значения для внутреннего использования. :)   -  person James Manning    schedule 15.10.2012
comment
Спасибо за ответы, Джеймс. Раньше я пробовал это, но если я изменю GetTestMethod () на использование await, тогда он также должен быть асинхронным, поэтому мне также нужно будет изменить его тип на Task ‹List ‹int››. И тогда у вызывающего абонента будет та же проблема, что и у GetTestMethod () сейчас?   -  person PaulR    schedule 15.10.2012
comment
Хорошо, теперь я думаю, что понимаю - если я сделаю GetTestMethod () недействительным, этого не произойдет. Но до тех пор, пока у метода есть возвращаемый тип, его вызывающая сторона также должна быть асинхронной и использовать ожидание в вызове и т. Д.   -  person PaulR    schedule 15.10.2012
comment
@PaulR, но если вы создадите метод async void, у вас нет возможности гарантировать, что он завершит выполнение; процесс может завершиться первым.   -  person phoog    schedule 15.10.2012
comment
Когда вы вызываете что-то, что возвращает Task, вам не нужно использовать await. Это действительно зависит от того, что звонящий должен с этим делать. Выстрелить и забыть? Запланировать продолжение на нем? Заблокировать до завершения? Что-то другое? Для метода тестирования, предполагая, что вы можете использовать тестовую среду, поддерживающую методы асинхронного тестирования, я бы использовал ожидание в методе тестирования асинхронности, но есть и другие варианты.   -  person James Manning    schedule 15.10.2012
comment
Спасибо всем за вашу помощь - вы позволили мне лучше понять это своими сообщениями. Думаю, я неправильно понял, откуда можно вызвать асинхронный метод - я хотел похоронить вызов где-нибудь в библиотеке вспомогательных функций. Но - в любом случае - в моем приложении - я думаю, что его нужно вызывать из обработчика событий, чтобы позволить системе использовать время ожидания.   -  person PaulR    schedule 15.10.2012


Ответы (3)


Основная проблема вашего примера в том, что вы не можете неявно преобразовать Task<T> возвращаемые типы в базовый T тип. Вам нужно использовать свойство Task.Result. Обратите внимание, что Task.Result блокирует асинхронный код, и его следует использовать осторожно.

Попробуйте вместо этого:

public List<int> TestGetMethod()  
{  
    return GetIdList().Result;  
}
person user2388853    schedule 04.06.2013
comment
Отлично работает - person saviour123; 23.09.2018
comment
@ Стивен Клири действительно - person Diego Venâncio; 19.05.2020

Вам также нужно сделать TestGetMethod async и прикрепить await перед GetIdList();, чтобы развернуть задачу в List<int>, поэтому, если ваша вспомогательная функция возвращает Task, убедитесь, что вы выполнили ожидание, поскольку вы также вызываете функцию async.

public Task<List<int>> TestGetMethod()
{
    return GetIdList();
}    

async Task<List<int>> GetIdList()
{
    using (HttpClient proxy = new HttpClient())
    {
        string response = await proxy.GetStringAsync("www.test.com");
        List<int> idList = JsonConvert.DeserializeObject<List<int>>();
        return idList;
    }
}

Другой вариант

public async void TestGetMethod(List<int> results)
{
    results = await GetIdList(); // await will unwrap the List<int>
}
person Mayank    schedule 14.10.2012
comment
Обратите внимание, что, поскольку в этом TestGetMethod больше ничего не происходит, развертывание + повторное обертывание - это немного глупо, и он может удалить async и await и просто вернуть GetIdList () :) - person James Manning; 15.10.2012
comment
зачем TestGetMethod должен быть async? - person dotNETbeginner; 02.02.2013

В зависимости от того, что вы пытаетесь сделать, вы можете либо заблокировать с помощью GetIdList (). Result (как правило, плохая идея, но сложно определить контекст), либо использовать тестовую среду, которая поддерживает методы асинхронного тестирования и сделать так, чтобы тестовый метод выполнял var results = ожидание GetIdList ();

person James Manning    schedule 14.10.2012