Howtoinitializeanobjectusingtheasync-awaitpattern,它是完全初始化的。但是,我在使用异步API时遇到了困难。相关类的结构如下classServiceProvider:IServiceProvider//仅通过此接口使用{publicintImportantValue{get;放;公共事件EventHandlerImportantValueUpdated;publicServiceProvider(IDependency1dep1,IDependency2dep2){//IDependency1提供一个输入值来计算ImportantValue//IDependency2提供一个异步算法来计算ImportantValue}}我的目标是消除ImportantValuegetter中的副作用并使其成为线程安全的。现在,ServiceProvider用户将创建它的一个实例,订阅ImportantValue更改事件,并获取原始ImportantValue。这就是问题所在,初始值。由于ImportantValue是异步计算的,因此无法在构造函数中完全初始化该类。最初将此值设置为null可能没问题,但我需要在某个地方第一次计算它。一个自然的地方可能是ImportantValue的吸气剂,但我的目标是使其线程安全且没有副作用。所以我基本上陷入了这些矛盾之中。你能帮我提供一些替代方案吗?在构造函数中初始化值不是很好,但是对于没有副作用和属性的线程安全是必需的。提前致谢。编辑:再补充一件事。我正在使用Ninject进行实例化,据我所知它不支持异步方法来创建绑定。虽然在构造函数中启动一些基于任务的操作的方法可行,但我等不及它的结果了。即接下来的两个方法(到目前为止提供的答案)不会编译,因为返回的是任务,而不是我的对象:Kernel.Bind().ToMethod(asyncctx=>awaitServiceProvider.CreateAsync())或Kernel。Bind().ToMethod(asyncctx=>{varsp=newServiceProvider();awaitsp.InitializeAsync();})简单的绑定会工作,但我不等待在构造函数中启动的异步初始化的结果,正如StephenCleary建议的那样:Kernel.Bind().To();……这对我来说不太好。我有一篇博文描述了异步构建的几种方法。我推荐Reed描述的异步工厂方法,但有时这是不可能的(例如,依赖注入)。在这些情况下,您可以使用如下异步初始化模式:publicsealedclassMyType{publicMyType(){Initialization=InitializeAsync();}公共任务初始化{get;私有集;}privateasyncTaskInitializeAsync(){//异步初始化这个实例。awaitTask.Delay(100);然后你就可以正常构造类型了,但是要记住,构造只会启动异步初始化。当你需要初始化一个类型时,你的代码可以做这样的事情:awaitmyTypeInstance.Initialization;请注意,如果初始化已经完成,则执行(同步)会在await之后继续。如果您确实想要一个实际的异步属性,我也有一篇关于它的博客文章。您的情况听起来可能会受益于AsyncLazy:publicsealedclassMyClass{publicMyClass(){MyProperty=newAsyncLazy(async()=>{awaitTask.Delay(100);return13;});}publicAsyncLazyMyProperty{get;私有集;一种可能的选择是将其移至工厂方法而不是使用构造函数。然后,您的工厂方法可以返回一个Task,它允许您异步执行初始化,但在(异步)计算ImportantValue之前不会返回构造的ServiceProvider。这将允许您的用户编写如下代码:varsp=awaitServiceProvider.CreateAsync();intiv=sp.ImportantValue;//将在此时初始化您可以使用我的AsyncContainerIoC容器,它支持与您的方案完全相同的方案。它还支持其他方便的场景,如异步初始化器、运行时条件工厂、依赖异步和同步工厂函数//电子邮件服务工厂是一个异步方法publicstaticasyncTaskEmailServiceFactory(){awaitTask.Delay(1000);返回新的电子邮件服务();}classService{//构造函数依赖将被异步解决:publicService(IEmailServiceemail){}}varcontainer=newContainer();//注册一个异步工厂:container.Register(EmailServiceFactory);//异步GetInstance:varservice=awaitcontainer.GetInstanceAsync();//安全同步,如果求解路径不完全同步会失败:varservice=container.GetInstance();这是对@StephenCleary的异步初始化模式Revise的轻微修改。不同之处在于调用者不需要“记住”等待InitializationTask,甚至不需要知道有关initializationTask的任何信息(实际上它现在已更改为私有)。它的工作方式是在每个使用初始化数据的方法中都有一个对await_initializationTask的初始调用。第二个立即返回-因为_initializationTask对象本身将有一个布尔集(IsCompleted由'await'机制检查)-所以不要担心它被多次初始化。我唯一知道的是你不能忘记在每个使用数据的方法中调用它。公共密封类MyType{publicMyType(){_initializationTask=InitializeAsync();}私有任务_initializationTask;privateasyncTaskInitializeAsync(){//异步初始化此实例。_customers=awaitLoadCustomersAsync();}publicasyncTaskLookupCustomer(stringname){//等待以确保类已正确初始化//任务只会运行一次,最初由构造函数触发//如果任务失败,这将引发异常//注意:没有()因为这不是方法调用await_initializationTask;返回_客户[姓名];}//一种清除缓存的方法publicvoidClearCache(){InitializeAsync();}//另一种清除缓存的方法,将等到完成//我真的看不到此方法的好处,因为任何使用//数据的调用(如LookupCustomer)都将等待初始化publicasyncTaskClearCache2(){等待InitializeAsync();}}我知道这是一个老问题,但这是谷歌上出现的第一个问题,坦率地说,接受的答案是一个糟糕的答案。你永远不应该强迫延迟,这样你就可以使用await运算符。更好的初始化方法:privateasyncTaskInitializeAsync(){try{//初始化这个实例。}catch{//处理问题returnawaitTask.FromResult(false);}返回等待Task.FromResult(true);这将使用异步框架初始化您的对象,但随后它将返回一个布尔值。为什么这是更好的方法?首先,您没有强迫代码延迟,恕我直言,这完全违背了使用异步框架的目的。其次,从异步方法返回一些东西是一个很好的经验法则。这样,您就知道您的异步方法是否真的有效/执行了它应该执行的操作。返回JustTask等同于在非异步方法上返回void。以上就是C#学习教程的全部内容:如何使用async-await方式初始化共享对象。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。涉及侵权,请点击维权联系管理员删除。如需转载请注明出处:
