C# как запустить метод имеющий возвращаемое значение в другом потоке?


#1

Для тренировки решил написать программу позволяющую редактировать txt файлы. С считыванием и редактированием файлов проблем не возникло, при запуске же метода сохранения файла столкнулся с проблемой, что во время процесса сохранения весь интерфейс программы становится недоступным, что не очень хорошо, ведь по задумке пользователь должен иметь возможность продолжить работать с файлом. Я логически пришёл к выводу, что процесс сохранения (метод отвечающий за сохранение) нужно запустить в другом потоке, но сделать это с помощью Thread не является возможным, потому что мой метод имеет возвращаемое значение (оно указывает успешно сохранился файл, или нет). И тут стал вопрос, нужно ли мне убрать возвращаемое значение метода для запуска его через Thread (чего не хотелось бы), или существует возможность его запуска во вторичном потоке с оставлением возвращаемого значения?


#2

Вы можете запустить выполнение данного метода асинхронно используя метод BeginInvoke у делегатов, который вернёт Вам экземпляр приведённый к интерфейсу IAsyncResult. После этого на делегате вызвать метод EndInvoke передавая ему полученный ранее экземпляр класса приведённого к интерфейсу IAsyncResult. Пример:

Func<int, int, int> myDelegate = new Func<int, int, int>((a, b) => a + b );

IAsyncResult asyncResult = myDelegate.BeginInvoke(1, 2, null, null);

// Получение результата асинхронной операции.
int result = myDelegate.EndInvoke(asyncResult);

Console.WriteLine("Результат = " + result);

Кроме этого варианта, также можно получить возвращаемое значение через использование задач (Tasks) или Фабрики задач (TaskFactory):

struct Arguments
{
    public int a;
    public int b;
}

static int Sum(object arg)
{
    int a = ((Arguments)arg).a;
    int b = ((Arguments)arg).b;

    Thread.Sleep(2000);

    return a + b;
}

Arguments args;
args.a = 2;
args.b = 3;

Task<int> task;

//  Tasks
task = new Task<int>(Sum, args);
task.Start();

//  TaskFactory
TaskFactory<int> factory = new TaskFactory<int>();
task = factory.StartNew(Sum, args);

Console.WriteLine("Sum = " + task.Result);

И последний вариант, это получение возвращаемого значения с использованием ключевых слов asunc/await:

static int a = 2;
static int b = 2;

public static async Task<int> OperationAsync()
{
    return await Task<int>.Factory.StartNew(() => a + b);
}

static void Main()
{
    Task<int> task = OperationAsync();

    task.ContinueWith(t => Console.WriteLine("Результат : {0}", t.Result));

    Console.ReadKey();
}

#3

Вы должны учитывать, что все наведённые выше способы имеют свои особенности работы, поэтому изначально знакомьтесь с ними. Для этого можете почитать Рихтера или посмотреть уроки посвящённые работе с потоками (например у ITVDN на курсе С# Proffesional)


#4

Всем спасибо!