async в переопределении контекста [дубликат]

Использовать параметризованный SQL.

Примеры

(Эти примеры приведены в C #, см. ниже для версии VB.NET.)

Замените свои конкатенации строк на @... заполнители, а затем добавьте значения в свой SqlCommand. Вы можете свободно выбирать имя заполнителей, просто убедитесь, что они начинаются с знака @. Ваш пример будет выглядеть так:

var sql = "INSERT INTO myTable (myField1, myField2) " +
          "VALUES (@someValue, @someOtherValue);";

using (var cmd = new SqlCommand(sql, myDbConnection))
{
    cmd.Parameters.AddWithValue("@someValue", someVariable);
    cmd.Parameters.AddWithValue("@someOtherValue", someTextBox.Text);
    cmd.ExecuteNonQuery();
}

Тот же шаблон используется для других видов операторов SQL:

var sql = "UPDATE myTable SET myField1 = @newValue WHERE myField2 = @someValue;";

// see above, same as INSERT

или

var sql = "SELECT myField1, myField2 FROM myTable WHERE myField3 = @someValue;";

using (var cmd = new SqlCommand(sql, myDbConnection))
{
    cmd.Parameters.AddWithValue("@someValue", someVariable);
    using (var reader = cmd.ExecuteReader())
    {
        ...
    }
    // Alternatively: object result = cmd.ExecuteScalar();
    // if you are only interested in one value of one row.
}

Предупреждение: AddWithValue является хорошей отправной точкой и прекрасно работает в большинстве случаев. Однако, что значение, которое вы передаете, должно точно соответствовать типу данных соответствующего поля базы данных. В противном случае вы можете оказаться в ситуации, когда преобразование предотвращает ваш запрос из с помощью индекса . Обратите внимание, что некоторые типы данных SQL Server, такие как char / varchar (без предшествующих «n») или даты, не имеют соответствующего типа данных .NET. В этих случаях вместо следует использовать Add с правильным типом данных.

Зачем мне это делать?

Другие библиотеки доступа к базе данных

507
задан Hamid Pourjam 28 June 2015 в 22:40
поделиться

22 ответа

Небольшая заметка - этот подход:

Task<Customer> task = GetCustomers();
task.Wait()

работает для WinRT.

Позвольте мне объяснить:

private void TestMethod()
{
    Task<Customer> task = GetCustomers(); // call async method as sync and get task as result
    task.Wait(); // wait executing the method
    var customer = task.Result; // get's result.
    Debug.WriteLine(customer.Name); //print customer name
}
public class Customer
{
    public Customer()
    {
        new ManualResetEvent(false).WaitOne(TimeSpan.FromSeconds(5));//wait 5 second (long term operation)
    }
    public string Name { get; set; }
}
private Task<Customer> GetCustomers()
{
    return Task.Run(() => new Customer
    {
        Name = "MyName"
    });
}

Кроме того, этот подход работает только для решений для Windows Store!

Примечание. Этот способ не является потокобезопасным, если вы вызываете свой метод внутри другого метода асинхронизации (согласно комментариям @Servy)

9
ответ дан animuson 1 September 2018 в 09:13
поделиться

Это хорошо работает для меня

public static class TaskHelper
{
    public static void RunTaskSynchronously(this Task t)
    {
        var task = Task.Run(async () => await t);
        task.Wait();
    }

    public static T RunTaskSynchronously<T>(this Task<T> t)
    {
        T res = default(T);
        var task = Task.Run(async () => res = await t);
        task.Wait();
        return res;
    }
}
21
ответ дан Clement 1 September 2018 в 09:13
поделиться

Я узнаю об async / await и столкнулся с ситуацией, когда мне нужно синхронно вызывать метод async. Как я могу это сделать?

Лучший ответ: нет, детали зависят от того, что такое «ситуация».

Это свойство getter / сеттер? В большинстве случаев лучше иметь асинхронные методы, чем «асинхронные свойства». (Для получения дополнительной информации см. мое сообщение в блоге о асинхронных свойствах ).

Является ли это MVVM-приложением и вы хотите выполнить привязку асинхронных данных? Затем используйте что-то вроде my NotifyTask , как описано в моей статье MSDN об асинхронной привязке данных .

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

Почти всегда есть лучший ответ, чем делать sync-over-async.

Если это невозможно для вашей ситуации (и вы знаете это, задав здесь вопрос , описывающий ситуацию ), я бы рекомендовал просто использовать синхронный код. Асинк всего наилучшего; синхронизация полностью наилучшая. Sync-over-async не рекомендуется.

Однако существует несколько ситуаций, когда требуется синхронизация по-асинхронному. В частности, вы ограничены вызывающим кодом, чтобы вы имели синхронизацию (и не имеете абсолютно никакого способа переосмыслить или переструктурировать свой код, чтобы разрешить асинхронность), и вы имеете для вызова асинхронного кода. Это очень редкая ситуация, но время от времени она появляется.

В этом случае вам нужно будет использовать один из хаков, описанный в моей статье о brownfield async development , в частности:

  • Блокировка (например, GetAwaiter().GetResult()). Обратите внимание, что это может вызвать взаимоблокировки (как я описываю в своем блоге).
  • Запуск кода в потоке пула потоков (например, Task.Run(..).GetAwaiter().GetResult()). Обратите внимание, что это будет работать, только если асинхронный код может быть запущен в потоке пула потоков (т. Е. Не зависит от контекста пользовательского интерфейса или ASP.NET).
  • Вложенные петли сообщений. Обратите внимание, что это будет работать, только если асинхронный код принимает только однопоточный контекст, а не специфический контекст (много UI и ASP.NET-кода ожидают определенный контекст).

Вложенные петли сообщений являются наиболее опасными из всех хаков, потому что это вызывает повторное включение . Re-entrancy чрезвычайно сложно понять, и (IMO) является причиной большинства ошибок приложений в Windows. В частности, если вы находитесь в потоке пользовательского интерфейса и блокируете рабочую очередь (ожидая завершения работы async), тогда CLR на самом деле выполняет некоторую пересылку сообщений для вас - на самом деле это будет обрабатывать некоторые сообщения Win32 из вашего кода . О, и вы не знаете, какие сообщения - когда Крис Брумме говорит: «Было бы здорово точно знать, что будет накачано? К сожалению, накачка - это черное искусство, которое находится за пределами смертного понимание. , тогда мы действительно не надеемся узнать.

Итак, когда вы блокируете это в потоке пользовательского интерфейса, вы просите о проблемах. Другая цитата из одной статьи: «Время от времени клиенты внутри или вне компании обнаруживают, что мы перекачиваем сообщения во время управляемой блокировки в STA [поток пользовательского интерфейса]. Это законная проблема, потому что они знают, что это очень сложно для написания кода, который является надежным перед лицом повторной установки ».

Да, это так. Очень сложно написать код, который является надежным в плане повторного размещения. И вложенные петли сообщений force вы должны написать код, который является надежным перед лицом повторной установки. Вот почему принятый (и наиболее востребованный) ответ на этот вопрос является чрезвычайно опасным на практике.

Если вы полностью вне всех других опции - вы не можете переконфигурировать свой код, вы не можете реструктурировать его как асинхронный - вы вынуждены неизменным кодом вызова для синхронизации - вы не можете изменить нисходящий код для синхронизации - вы не можете блокировать - вы не может запускать асинхронный код в отдельном потоке - тогда и только после этого вы должны рассмотреть возможность включения reentrancy.

Если вы окажетесь в этом углу, я бы рекомендовал использовать что-то например Dispatcher.PushFrame для приложений WPF , зацикливание с помощью Application.DoEvents для приложений WinForm и для общего случая, мой собственный AsyncContext.Run .

36
ответ дан Community 1 September 2018 в 09:13
поделиться

Этот ответ предназначен для всех, кто использует WPF для .NET 4.5.

Если вы попытаетесь выполнить Task.Run() в потоке GUI, тогда task.Wait() будет вешать бесконечно, если вы не имеют ключевое слово async в определении вашей функции.

Этот метод расширения решает проблему, проверяя, есть ли мы в потоке графического интерфейса пользователя, и если да, выполняем задачу в потоке диспетчера WPF.

Этот класс может действовать как клей между миром async / await и неасинхронным / ожидающим миром в ситуациях, когда это неизбежно, например свойства MVVM или зависимости от других API, которые не используют async / ожидают.

/// <summary>
///     Intent: runs an async/await task synchronously. Designed for use with WPF.
///     Normally, under WPF, if task.Wait() is executed on the GUI thread without async
///     in the function signature, it will hang with a threading deadlock, this class 
///     solves that problem.
/// </summary>
public static class TaskHelper
{
    public static void MyRunTaskSynchronously(this Task task)
    {
        if (MyIfWpfDispatcherThread)
        {
            var result = Dispatcher.CurrentDispatcher.InvokeAsync(async () => { await task; });
            result.Wait();
            if (result.Status != DispatcherOperationStatus.Completed)
            {
                throw new Exception("Error E99213. Task did not run to completion.");
            }
        }
        else
        {
            task.Wait();
            if (task.Status != TaskStatus.RanToCompletion)
            {
                throw new Exception("Error E33213. Task did not run to completion.");
            }
        }
    }

    public static T MyRunTaskSynchronously<T>(this Task<T> task)
    {       
        if (MyIfWpfDispatcherThread)
        {
            T res = default(T);
            var result = Dispatcher.CurrentDispatcher.InvokeAsync(async () => { res = await task; });
            result.Wait();
            if (result.Status != DispatcherOperationStatus.Completed)
            {
                throw new Exception("Error E89213. Task did not run to completion.");
            }
            return res;
        }
        else
        {
            T res = default(T);
            var result = Task.Run(async () => res = await task);
            result.Wait();
            if (result.Status != TaskStatus.RanToCompletion)
            {
                throw new Exception("Error E12823. Task did not run to completion.");
            }
            return res;
        }
    }

    /// <summary>
    ///     If the task is running on the WPF dispatcher thread.
    /// </summary>
    public static bool MyIfWpfDispatcherThread
    {
        get
        {
            return Application.Current.Dispatcher.CheckAccess();
        }
    }
}
3
ответ дан Contango 1 September 2018 в 09:13
поделиться

В вашем коде ваше первое ожидание выполнения задачи, но вы не запустили ее, так что она ждет бесконечно. Попробуйте следующее:

Task<Customer> task = GetCustomers();
task.RunSynchronously();

Изменить:

Вы говорите, что получаете исключение. Пожалуйста, напишите более подробную информацию, включая трассировку стека. Mono содержит следующий тестовый пример:

[Test]
public void ExecuteSynchronouslyTest ()
{
        var val = 0;
        Task t = new Task (() => { Thread.Sleep (100); val = 1; });
        t.RunSynchronously ();

        Assert.AreEqual (1, val);
}

Проверьте, работает ли это для вас. Если это не так, но очень маловероятно, у вас может быть некоторая нечетная сборка Async CTP. Если это сработает, вам может потребоваться изучить, что именно генерирует компилятор, и как Task экземпляр отличается от этого образца.

Редактировать # 2:

Я проверил с Reflector, что описанное вами исключение возникает, когда m_action - null. Это странно, но я не эксперт в Async CTP. Как я уже сказал, вы должны декомпилировать свой код и посмотреть, как именно создается Task, каким образом его m_action является null.


P.S. В чем дело с случайными сокращениями? Учиться разрабатывать?

8
ответ дан Dan Abramov 1 September 2018 в 09:13
поделиться

Это работает для меня

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    public static class AsyncHelper
    {
        private static readonly TaskFactory _myTaskFactory = new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);

        public static void RunSync(Func<Task> func)
        {
            _myTaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult();
        }

        public static TResult RunSync<TResult>(Func<Task<TResult>> func)
        {
            return _myTaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult();
        }
    }

    class SomeClass
    {
        public async Task<object> LoginAsync(object loginInfo)
        {
            return await Task.FromResult(0);
        }
        public object Login(object loginInfo)
        {
            return AsyncHelper.RunSync(() => LoginAsync(loginInfo));
            //return this.LoginAsync(loginInfo).Result.Content;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var someClass = new SomeClass();

            Console.WriteLine(someClass.Login(1));
            Console.ReadLine();
        }
    }
}
-1
ответ дан Dan Nguyen 1 September 2018 в 09:13
поделиться

Почему бы не создать такой вызов, как:

Service.GetCustomers();

, который не является асинхронным.

7
ответ дан Daniel A. White 1 September 2018 в 09:13
поделиться

Я думаю, что следующий вспомогательный метод также может решить проблему.

private TResult InvokeAsyncFuncSynchronously<TResult>(Func< Task<TResult>> func)
    {
        TResult result = default(TResult);
        var autoResetEvent = new AutoResetEvent(false);

        Task.Run(async () =>
        {
            try
            {
                result = await func();
            }
            catch (Exception exc)
            {
                mErrorLogger.LogError(exc.ToString());
            }
            finally
            {
                autoResetEvent.Set();
            }
        });
        autoResetEvent.WaitOne();

        return result;
    }

Может использоваться следующим образом:

InvokeAsyncFuncSynchronously(Service.GetCustomersAsync);
1
ответ дан donttellya 1 September 2018 в 09:13
поделиться

Я столкнулся с этим несколько раз, в основном в модульном тестировании или в разработке служб Windows. В настоящее время я всегда использую эту функцию:

        var runSync = Task.Factory.StartNew(new Func<Task>(async () =>
        {
            Trace.WriteLine("Task runSync Start");
            await TaskEx.Delay(2000); // Simulates a method that returns a task and
                                      // inside it is possible that there
                                      // async keywords or anothers tasks
            Trace.WriteLine("Task runSync Completed");
        })).Unwrap();
        Trace.WriteLine("Before runSync Wait");
        runSync.Wait();
        Trace.WriteLine("After runSync Waited");

Это просто, легко, и у меня не было проблем.

15
ответ дан J. Lennon 1 September 2018 в 09:13
поделиться

Удивленный никто не упомянул об этом:

public Task<int> BlahAsync()
{
    // ...
}

int result = BlahAsync().GetAwaiter().GetResult();

Не так хорошо, как некоторые из других методов здесь, но он имеет следующие преимущества:

  • )
  • не будет содержать никаких исключений, которые были выбраны в AggregateException (например Result)
  • работает как для Task, так и для Task<T> ( попробуйте сами! )

Кроме того, поскольку GetAwaiter утиный, это должно работать для любого объекта, который возвращается из async (например, ConfiguredAwaitable или YieldAwaitable), а не только Задачи.


edit: Обратите внимание, что этот подход (или использование .Result) возможен в тупик, если вы не убедитесь добавлять .ConfigureAwait(false) каждый раз, когда вы ожидаете, для всех асинхронных методов, которые могут быть достигнуты с BlahAsync() (а не только с теми, которые он вызывает напрямую). Объяснение .

// In BlahAsync() body
await FooAsync(); // BAD!
await FooAsync().ConfigureAwait(false); // Good... but make sure FooAsync() and
                                        // all its descendants use ConfigureAwait(false)
                                        // too. Then you can be sure that
                                        // BlahAsync().GetAwaiter().GetResult()
                                        // won't deadlock.

Если вы слишком ленивы, чтобы добавить .ConfigureAwait(false) повсюду, и вы не заботитесь о производительности, вы также можете сделать

Task.Run(() => BlahAsync()).GetAwaiter().GetResult()
77
ответ дан James Ko 1 September 2018 в 09:13
поделиться

Вы можете использовать CoRoutines . См. Реализацию Caliburn.Micro . У меня есть пользовательская реализация здесь .

0
ответ дан Jone Polvora 1 September 2018 в 09:13
поделиться
    private int GetSync()
    {
        try
        {
            ManualResetEvent mre = new ManualResetEvent(false);
            int result = null;

            Parallel.Invoke(async () =>
            {
                result = await SomeCalcAsync(5+5);
                mre.Set();
            });

            mre.WaitOne();
            return result;
        }
        catch (Exception)
        {
            return null;
        }
    }
-4
ответ дан ksemenenko 1 September 2018 в 09:13
поделиться

использовать ниже код snip

Task.WaitAll(Task.Run(async () => await service.myAsyncMethod()));
5
ответ дан Mahesh 1 September 2018 в 09:13
поделиться

Попробуйте использовать следующий код для меня:

public async void TaskSearchOnTaskList (SearchModel searchModel)
{
    try
    {
        List<EventsTasksModel> taskSearchList = await Task.Run(
            () => MakeasyncSearchRequest(searchModel),
            cancelTaskSearchToken.Token);

        if (cancelTaskSearchToken.IsCancellationRequested
                || string.IsNullOrEmpty(rid_agendaview_search_eventsbox.Text))
        {
            return;
        }

        if (taskSearchList == null || taskSearchList[0].result == Constants.ZERO)
        {
            RunOnUiThread(() => {
                textViewNoMembers.Visibility = ViewStates.Visible;                  
                taskListView.Visibility = ViewStates.Gone;
            });

            taskSearchRecureList = null;

            return;
        }
        else
        {
            taskSearchRecureList = TaskFooterServiceLayer
                                       .GetRecurringEvent(taskSearchList);

            this.SetOnAdapter(taskSearchRecureList);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine("ActivityTaskFooter -> TaskSearchOnTaskList:" + ex.Message);
    }
}
-9
ответ дан Massimiliano Kraus 1 September 2018 в 09:13
поделиться

Гораздо проще запустить задачу в пуле потоков, а не пытаться обмануть планировщика для его синхронного запуска. Таким образом, вы можете быть уверены, что это не затормозит. Эффект зависит от контекстного переключателя.

Task<MyResult> DoSomethingAsync() { ... }

// Starts the asynchronous task on a thread-pool thread.
// Returns a proxy to the original task.
Task<MyResult> task = Task.Run(() => DoSomethingAsync());

// Will block until the task is completed...
MyResult result = task.Result; 
64
ответ дан Michael L Perry 1 September 2018 в 09:13
поделиться

Просто вызов .Result; или .Wait() - это риск блокировок, о котором многие говорили в комментариях. Поскольку большинство из нас, как oneliners, вы можете использовать их для .Net 4.5<

Приобретение значения с помощью метода async:

var result = Task.Run(() => asyncGetValue()).Result;

Синхронно вызывать метод асинхронизации

Task.Run(() => asyncMethod()).Wait();

Никаких проблем с блокировкой не произойдет из-за использования Task.Run.

Источник:

https://stackoverflow.com/a/32429753/3850405

3
ответ дан Ogglas 1 September 2018 в 09:13
поделиться

Самый простой способ, который я нашел для запуска задачи синхронно и без блокировки потока пользовательского интерфейса, - использовать RunSynchronously () как:

Task t = new Task(() => 
{ 
   //.... YOUR CODE ....
});
t.RunSynchronously();

В моем случае у меня есть событие, которое срабатывает, когда что-то происходит. Я не знаю, сколько раз это произойдет. Таким образом, я использую код выше в моем случае, поэтому всякий раз, когда он срабатывает, он создает задачу. Задачи выполняются синхронно, и это отлично работает для меня. Я был просто удивлен, что мне потребовалось столько времени, чтобы выяснить, насколько это просто. Обычно рекомендации намного сложнее и подвержены ошибкам. Это было просто и чисто.

16
ответ дан pixel 1 September 2018 в 09:13
поделиться

Если я правильно читаю ваш вопрос - код, который хочет, чтобы синхронный вызов метода асинхронизации выполнялся в приостановленном потоке диспетчера. И вы хотите фактически синхронизировать этот поток до тех пор, пока не будет завершен метод async.

Асинхронные методы на C # 5 приводятся в действие путем эффективного измельчения метода на куски под капотом и возвращения Task, который может отслеживать общее завершение всего шабанга. Однако, как выполняются методы прерывания, может зависеть от типа выражения, переданного оператору await.

В большинстве случаев вы будете использовать await для выражения типа Task. Выполнение задачи await шаблона является «умным», поскольку оно отбрасывает SynchronizationContext, что в основном приводит к следующему:

  1. Если поток, входящий в await, включен поток потока сообщений диспетчера или WinForms, он гарантирует, что куски асинхронного метода выполняются как часть обработки очереди сообщений.
  2. Если поток, входящий в await, находится в потоке пула потоков, то оставшиеся куски асинхронного метода встречаются в любом месте пула потоков.

Вот почему вы, вероятно, сталкиваетесь с проблемами - реализация метода асинхронного тестирования пытается запустить остальные на диспетчере - даже если он приостановлен.

.... резервное копирование! ....

Я должен задать вопрос, , почему вы пытаетесь синхронно блокировать метод async? Это может привести к тому, что метод будет вызван асинхронно. В общем случае, когда вы начинаете использовать await в методе Dispatcher или UI, вам нужно будет перевернуть весь ваш асинхронный поток пользовательского интерфейса. Например, если ваш столбец был примерно таким:

  1. [Вверх] WebRequest.GetResponse()
  2. YourCode.HelperMethod()
  3. YourCode.AnotherMethod()
  4. YourCode.EventHandlerMethod()
  5. [UI Code].Plumbing() - WPF или WinForms Код
  6. [Message Loop] - WPF или WinForms Message Loop

Затем, как только код был преобразован для использования async, вы, как правило, получите

  1. [Вверх] WebRequest.GetResponseAsync()
  2. YourCode.HelperMethodAsync()
  3. YourCode.AnotherMethodAsync()
  4. YourCode.EventHandlerMethodAsync()
  5. [UI Code].Plumbing() - WPF или WinForms Код
  6. [ Message Loop] - WPF или WinForms Message Loop

Фактически Ответ

Класс AsyncHelpers выше фактически работает, потому что он ведет себя как вложенный цикл сообщений, но он устанавливает свой собственный параллельный механизм в диспетчер, вместо того, чтобы пытаться выполнить сам Диспетчер. Это один из способов решения вашей проблемы.

Другим обходным решением является выполнение вашего асинхронного метода в потоке threadpool, а затем дождаться его завершения. Делать это легко - вы можете сделать это со следующим фрагментом:

var customerList = TaskEx.RunEx(GetCustomers).Result;

Конечным API будет Task.Run (...), но с CTP вам понадобятся суффиксы Ex ( здесь ).

18
ответ дан Prateek 1 September 2018 в 09:13
поделиться

Рекомендовать этому ответу три года. Я написал его, основываясь главным образом на опыте с .Net 4.0 и очень мало с 4.5, особенно с async-await. Вообще говоря, это приятное простое решение, но иногда это ломает ситуацию. Пожалуйста, прочитайте обсуждение в комментариях.

.Net 4.5

Просто используйте это:

// For Task<T>: will block until the task is completed...
var result = task.Result; 

// For Task (not Task<T>): will block until the task is completed...
task2.RunSynchronously();

См.: TaskAwaiter , Task.Result , Task.RunSynchronously


.Net 4.0

Используйте это:

var x = (IAsyncResult)task;
task.Start();

x.AsyncWaitHandle.WaitOne();

... или это:

task.Start();
task.Wait();
287
ответ дан Rachel 1 September 2018 в 09:13
поделиться

Или вы могли бы просто пойти с:

customerList = Task.Run<List<Customer>>(() => { return GetCustomers(); }).Result;

Для этого для компиляции убедитесь, что вы ссылаетесь на сборку:

System.Net.Http.Formatting
-4
ответ дан tinlyx 1 September 2018 в 09:13
поделиться

В wp8:

Оберните его:

Task GetCustomersSynchronously()
{
    Task t = new Task(async () =>
    {
        myCustomers = await GetCustomers();
    }
    t.RunSynchronously();
}

Вызовите его:

GetCustomersSynchronously();
-3
ответ дан user2113284 1 September 2018 в 09:13
поделиться

Я нашел этот код в компоненте Microsoft.AspNet.Identity.Core, и он работает.

private static readonly TaskFactory _myTaskFactory = new 
     TaskFactory(CancellationToken.None, TaskCreationOptions.None, 
     TaskContinuationOptions.None, TaskScheduler.Default);

// Microsoft.AspNet.Identity.AsyncHelper
public static TResult RunSync<TResult>(Func<Task<TResult>> func)
{
    CultureInfo cultureUi = CultureInfo.CurrentUICulture;
    CultureInfo culture = CultureInfo.CurrentCulture;
    return AsyncHelper._myTaskFactory.StartNew<Task<TResult>>(delegate
    {
        Thread.CurrentThread.CurrentCulture = culture;
        Thread.CurrentThread.CurrentUICulture = cultureUi;
        return func();
    }).Unwrap<TResult>().GetAwaiter().GetResult();
}
12
ответ дан wenhx 1 September 2018 в 09:13
поделиться
Другие вопросы по тегам:

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