62.异步编程+Prism
为什么不需要在构造函数中初始化了?
private ICommand _fetchUserInfoCommand;
public ICommand FetchUserInfoCommand => _fetchUserInfoCommand ??= new DelegateCommand(ExecuteFetchUserInfoAsync);
public MainWindowViewModel()
{
// 无需在构造函数中显式创建命令实例,因为使用了延迟初始化(??=)
}
原本的样子:
public ICommand FetchUserInfoCommand { get; }
public MainWindowViewModel()
{
FetchUserInfoCommand = new RelayCommand(async (param) => await FetchUserInfoAsync());
}
在C#中,??=
是一个空合并赋值运算符,它用于为可为空的变量或具有默认值类型的变量提供一个简洁的赋值方式,当且仅当该变量当前为 null
(对于引用类型)或默认值(对于值类型)时。
在Prism框架的上下文中,当你将命令属性定义为只读并希望它在首次被访问时才被创建时,可以使用 ??=
运算符来实现延迟初始化。这种方法的好处是,它避免了在构造函数中不必要的初始化开销,特别是当命令的创建涉及复杂逻辑或资源消耗时。
当你第一次尝试访问 FetchUserInfoCommand
属性时,C# 会检查 _fetchUserInfoCommand
字段是否为 null
。如果是,它会执行 ??=
右侧的表达式,即创建一个新的 DelegateCommand
实例,并将其赋值给 _fetchUserInfoCommand
。之后,每次访问 FetchUserInfoCommand
属性时,都会直接返回这个已经创建的命令实例,而不会再次执行初始化代码。
这种延迟初始化的技术有助于提升应用程序的性能和响应性,因为它允许你按需创建对象,而不是在应用程序启动时立即创建所有可能需要的对象。
void和Task的区别
private async void ExecuteFetchUserInfoAsync();
private async Task ExecuteFetchUserInfoAsync();
在C#中,按钮点击等事件处理常使用async void
,因其需匹配返回void
的委托类型。但使用async void
需谨慎:它不可被await
,且异常需内部处理,否则可能导致崩溃。对于非事件处理的长时间运行任务,async Task
更佳,因可await
其完成,用try-catch
捕获异常,并支持取消。选择时,需考虑方法用途、是否需要等待、异常处理及是否事件处理。非事件处理且需等待和错误处理时,应选async Task
。
后台代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.Common;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace 异步
{
public class MainWindowViewModel : BindableBase
{
// 声明命令
private ICommand _fetchUserInfoCommand;
public ICommand FetchUserInfoCommand => _fetchUserInfoCommand ??= new DelegateCommand(ExecuteFetchUserInfoAsync);
// 用户信息属性
private string _userInfo;
public string UserInfo
{
get => _userInfo;
set => SetProperty(ref _userInfo, value); // 使用SetProperty进行属性变更通知(如果继承了BindableBase)
}
// 异步执行方法
private async void ExecuteFetchUserInfoAsync()
{
// 模拟异步操作,比如网络请求
await Task.Delay(2000); // 模拟网络延迟
UserInfo = "用户信息:新员工,需要学会WPF的异步,并巩固之前的知识。";
}
// 构造函数
public MainWindowViewModel()
{
// 无需在构造函数中显式创建命令实例,因为使用了延迟初始化(??=)
}
}
}
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace 异步
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext=new MainWindowViewModel();
}
}
}
前台:
<Window x:Class="异步.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:异步"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<StackPanel>
<Button Content="获取用户信息" Command="{Binding FetchUserInfoCommand}" Margin="10"/>
<TextBox Text="{Binding UserInfo, UpdateSourceTrigger=PropertyChanged}" Margin="10,20,10,10" TextWrapping="Wrap" Height="100"/>
</StackPanel>
</Grid>
</Window>