我有一个有2个集合的视图模型,它从数据库中获取数据.例如,增值税的国家和类型.

我想将这个集合的初始化推迟到我会的时候,因为如果我没有错的话,最好不要在构造函数中这样做,因为它是一个高成本的资源,并且构造函数的创建成本必须很低.

因此,我try 使用的一个选项是延迟初始化.this is the documentation.

但我使用的代码略有不同,因为从数据库获取数据的方法是异步的.

这是我的视图模型:

public class MyViewModel
{
    //Service to get data from database.
    private readonly IDataService _dataService;



    //The service is injected with dependency injection.
    public MyViewModel(IDataService paramDataService)
    {
        _dataService = paramDataService;


        _countriesoOc = new Lazy<Task<ObservableCollection<Contry>>>(InitializeContriesAsync);
        _vatsoOc = new Lazy<Task<ObservableCollection<VAT>>>(InitializeVatsAsync);
    }



    private readonly Lazy<Task<ObservableCollection<Country>>> _countriesOc;
    public IReadOnlyCollection<Cauntry> Coutries => _countriesOc.Value.Result;

    public Country? SelectedCountry;


    private async Task<ObservableCollection<MagnitudDTO>> InitializeCountriesAsync()
    {
        //Tset long process
        await Task.Delay(5000).ConfigureAwait(false);
        return new ObservableCollection<Contry>(await _dataService.GetAllContriesAsync().ConfigureAwait(false));
    }



    private readonly Lazy<Task<ObservableCollection<VAT>>> _vatsOc;
    public IReadOnlyCollection<VAT> Vats => _vatsOc.Value.Result;

    public VAT? SelectedVat;


    private async Task<ObservableCollection<VAT>> InitializeVatsAsync()
    {
        //Tset long process
        await Task.Delay(5000).ConfigureAwait(false);
        return new ObservableCollection<VAT>(await _dataService.GetAllVatsAsync().ConfigureAwait(false));
    }



    public void SetInvoce(Invoce paramInvoce)
    {
        SelectedCountry = _countriesOc.FirstOrDefault(x => x.Id = paramInvoce.IdCountry);
        SelectedVat = _vatsOc.FirstOrDefault(x => x.Id = paramInvoce.IdVat);
    }
}

我意识到在这种情况下,当我设置第一张发票时,它需要10秒,因为当它设置国家/地区时,它似乎等待了5秒的初始化,然后继续设置增值税,这又需要5秒.

有什么方法可以将所选项目设置为并行的吗?我猜也许我在集合中使用.Result属性是错误的,但我不确定.

我会try 另一种 Select ,即使用并行运行所有方法的intilze方法.以下是解决方案:

public class MyViewModel
{
    //Service to get data from database.
    private readonly IDataService _dataService;



    //The service is injected with dependency injection.
    public MyViewModel(IDataService paramDataService)
    {
        _dataService = paramDataService;
    }


    public Task InitializeAsync()
    {
        return Task.WhenAll(IntializeCountriesAsync(), InitializeVatsAsync());
    }


    private readonly ObservableCollection<Country> _countriesOc;
    public IReadOnlyCollection<Cauntry> Coutries => _countriesOc;

    public Country? SelectedCountry;


    private async Task<ObservableCollection<MagnitudDTO>> InitializeCountriesAsync()
    {
        //Tset long process
        await Task.Delay(5000).ConfigureAwait(true);
        _countriesOc.AddRange(await _dataService.GetAllCountriesAsync().ConfigureAwait(true));
    }



    private readonly Lazy<Task<ObservableCollection<VAT>>> _vatsOc;
    public IReadOnlyCollection<VAT> Vats => _vatsOc.Value.Result;

    public VAT? SelectedVat;


    private async Task<ObservableCollection<VAT>> InitializeVatsAsync()
    {
        //Tset long process
        await Task.Delay(5000).ConfigureAwait(true);
        _vatsOc.AddRange(await _dataService.GetAllVatsAsync().ConfigureAwait(true));
    }



    public void SetInvoce(Invoce paramInvoce)
    {
        SelectedCountry = _countriesOc.FirstOrDefault(x => x.Id = paramInvoce.IdCountry);
        SelectedVat = _vatsOc.FirstOrDefault(x => x.Id = paramInvoce.IdVat);
    }
}

在本例中,使用视图模型的每个对象都从依赖项注入中获取实例,但它必须调用InitializeAsync()方法来填充集合.

此解决方案的优点是初始化需要5秒,因为所有集合都是并行初始化的.但我不喜欢每个使用视图模型的对象都必须对其进行初始化.对于消费者来说,异步懒惰解决方案不那么透明,但它的速度要快得多.如果我有许多集合,它们是并行初始化的.

总而言之,我想知道是否有一些方法可以改进异步延迟解决方案以并行运行初始化,如果没有,我想我会 Select 第二个解决方案,尽管每个使用者在使用它之前总是必须调用初始化方法.

谢谢.

推荐答案

第二个选项可以重写为:

public class MyViewModel
{
    private readonly IDataService _dataService;
    private readonly Lazy<Task> InitTask;

    public MyViewModel(IDataService paramDataService)
    {
        _dataService = paramDataService;
        InitTask = new Lazy<Task>(Task.WhenAll(IntializeCountriesAsync(), InitializeVatsAsync()));
    }

    // ...
    public void SetInvoce(Invoce paramInvoce)
    {
        InitTask.Value.Wait();
        SelectedCountry = _countriesOc.FirstOrDefault(x => x.Id = paramInvoce.IdCountry);
        SelectedVat = _vatsOc.FirstOrDefault(x => x.Id = paramInvoce.IdVat);
    }
}

不过,就我个人而言,我强烈建议大家遵循这个建议,不要block on async code,也要让SetInvoce同步:

public async Task SetInvoce(Invoce paramInvoce)
{
    await InitTask.Value.ConfigureAwait(false);
    SelectedCountry = _countriesOc.FirstOrDefault(x => x.Id = paramInvoce.IdCountry);
    SelectedVat = _vatsOc.FirstOrDefault(x => x.Id = paramInvoce.IdVat);
}

如果这是一种 Select ,那么我将丢弃第一种情况的"同步包装器",只做如下操作:

public async Task SetInvoce(Invoce paramInvoce)
{
    await Task.WhenAll(_countriesoOc.Value, _vatsoOc.Value).ConfigureAwait(false);
    SelectedCountry = _countriesoOc.Result.FirstOrDefault(x => x.Id = paramInvoce.IdCountry);
    SelectedVat = _vatsOc.Result.FirstOrDefault(x => x.Id = paramInvoce.IdVat);
}

或者,你可以考虑利用in-memory cache.

Csharp相关问答推荐

VS Code - C# - dotnet run找不到文件,但我可以打开并编辑它们吗?

[0-n]范围内有多少个Integer在其小数表示中至少包含一个9?

Rx.Net -当关闭序列被触发时如何聚合消息并发出中间输出?

Serilog SQL服务器接收器使用UTC作为时间戳

更改对象的旋转方向

如何使用C#和Graph API从Azure Directory获取用户详细信息

MongoDB将JS查询转换为C#的问题

C#EF Core 8.0表现与预期不符

XUNIT是否使用测试数据的源生成器?

在命名管道上使用GRPC ASP.NET核心时如何配置命名管道权限

ASP.NET Core AutoMapper:如何解决错误 CS0121调用在以下方法或属性之间不明确

在.NET MAUI.NET 8中如何防止按钮点击时出现灰色反馈

为基本审计设置Audit.EntityFramework.Core

是否可以在Entity Framework Core中使用只读 struct 作为拥有实体?

类/值和日期的泛型方法

Maui:更改代码中的绑定字符串不会更新UI,除非重新生成字符串(MVVM)

如何使用LINQ在C#中填充列表列表?

ASP.NET核心中的授权,如何在DbContext启动之前提供租用ID

C#-如何将int引用获取到byte[]

最小API定义的Swagger标头参数