В C # 7.3 у вас могут быть асинхронные точки входа, я предлагаю использовать это.
Некоторые примечания:
Task.WhenAll
Модифицированный пример
static async Task Main(string[] args)
{
Console.WriteLine("Start Task");
var task = Program.step1();
for (int i = 0; i < 6; i++)
{
await Task.Delay(100);
Console.WriteLine("Sleep-Loop");
}
Console.WriteLine("waiting for the task to finish");
await task;
Console.WriteLine("finished");
Console.ReadKey();
}
private static async Task step1()
{
await Task.Delay(1000);
Console.WriteLine("Step1");
await Program.step2();
}
private static async Task step2()
{
await Task.Delay(1000);
Console.WriteLine("Step2");
}
Важно отметить, что задачи не являются потоками и async
не параллельны, однако они могут быть.
9 раз из 10, если вы используете шаблон асинхронного ожидания, работа, связанная с вводом-выводом, должна использовать порты завершения ввода-вывода операционной системы, чтобы вы могли освободить потоки. Это функция масштабируемости и отзывчивости пользовательского интерфейса.
Если вы не выполняете какую-либо работу ввода-вывода, тогда на самом деле совсем нет нужды в паттерне async
await
, и, как следствие, такая работа процессора, вероятно, должна быть просто заключена в Task.Run
в точке вызова. Не упакован в методе async
.
На этом этапе также полезно отметить, что использование только задач не является асинхронным и ожидающим шаблоном. Хотя у них обоих есть общие задачи, они не одно и то же.
И последнее; если вы считаете, что вам нужно использовать асинхронный код с огнем и забыть, очень тщательно подумайте, как вы будете обрабатывать любые ошибки.
Вот несколько рекомендаций.
Task.Run
await
ее, никогда не вызывайте Result
или [ 1110] или используйте Task.WhenAll
Re ваша головоломка; Я предполагаю stringifyList
является универсальным методом? Вам нужно вызвать его с помощью отражения:
MethodInfo method = typeof(SomeType).GetMethod("stringifyList")
.MakeGenericMethod(lt).Invoke({target}, new object[] {o});
, где {target}
равно null
для статического метода, или this
для метода экземпляра на текущем экземпляр.
Далее - я бы не предположил, что все коллекции являются: основанными на List
, b: универсальными типами. Важно то, что они реализуют IList
для некоторого T
?
Вот полный пример:
using System;
using System.Collections.Generic;
static class Program {
static Type GetListType(Type type) {
foreach (Type intType in type.GetInterfaces()) {
if (intType.IsGenericType
&& intType.GetGenericTypeDefinition() == typeof(IList<>)) {
return intType.GetGenericArguments()[0];
}
}
return null;
}
static void Main() {
object o = new List<int> { 1, 2, 3, 4, 5 };
Type t = o.GetType();
Type lt = GetListType(t);
if (lt != null) {
typeof(Program).GetMethod("StringifyList")
.MakeGenericMethod(lt).Invoke(null,
new object[] { o });
}
}
public static void StringifyList<T>(IList<T> list) {
Console.WriteLine("Working with " + typeof(T).Name);
}
}
Используйте Type для сбора необходимой информации.
Для универсальных объектов вызовите GetType (), чтобы получить их тип и затем проверьте IsGenericType
, чтобы узнать, является ли он универсальным вообще. Если это так, вы можете получить определение универсального типа, которое можно сравнить, например, так: typeof (List <>) == yourType.GetGenericTypeDefinition ()
.
Чтобы выяснить, что такое универсальные типы, используйте метод GetGenericArguments
, который будет возвращать массив используемых типов.
Для сравнения типов вы можете сделать следующее: if (typeof ( int) .IsAssignableFrom (yourGenericTypeArgument))
.
РЕДАКТИРОВАТЬ, чтобы ответить на продолжение:
Просто заставьте ваш метод stringifyList
принять IEnumerable
(не универсальный) в качестве параметра и может быть, также известный аргумент обобщенного типа, и вы будете в порядке; затем вы можете использовать foreach
, чтобы просмотреть все элементы и обработать их в зависимости от аргумента типа, если это необходимо.
На самом базовом уровне все универсальные списки реализуют IEnumerable
, который находится в сам потомок IEnumerable
. Если вы хотите сериализовать список, то вы можете просто привести его к IEnumerable и перечислить общие объекты внутри него.
Причина, по которой вы не можете сделать
Type lt = t.GetGenericArguments()[0];
List<lt> x = (List<lt>)o;
stringifyList(x);
, заключается в том, что обобщенные типы все еще должны быть статически строго типизированы, и что вы пытаетесь сделать, это создать динамический тип. List
и List
, несмотря на использование одного и того же универсального интерфейса, представляют собой два совершенно разных типа, и вы не можете привести их между собой.
List<int> intList = new List<int>();
List<string> strList = intList; // error!
Какой тип получит stringifyList (x)
? Самый базовый интерфейс, который вы можете здесь передать, это IEnumerable
, так как IList
не наследуется от IList
.
Чтобы сериализовать общий список, вам необходимо сохранить информацию об исходном типе списка, чтобы его можно было заново создать с помощью Activator
. Если вы хотите немного оптимизировать систему, чтобы вам не приходилось проверять тип каждого члена списка в вашем методе stringify, вы можете напрямую передать тип, извлеченный из списка.