使用 MetadataUpdateHandler 扩展 .NET 热重载(C#、Visual Basic)

可以编程方式扩展 .NET 热重载,来支持其他通常不支持的场景,例如需要清除缓存或刷新 UI 的代码更改。 例如,若要支持 JSON 序列化程序的热重载,需要在修改类型时清除其缓存。 对于 .NET MAUI 开发人员,可能需要扩展热重载,使其用于在正常条件下不触发热重载的编辑/更新,例如编辑构造函数,或者 UI 元素的事件处理程序。 可使用 MetadataUpdateHandlerAttribute 刷新应用程序状态、触发 UI 重新呈现或执行类似的操作。

此属性指定的类型应实现与下面一个或多个内容的签名匹配的静态方法:

static void ClearCache(Type[]? updatedTypes)
static void UpdateApplication(Type[]? updatedTypes)

ClearCache 使更新处理程序有机会清除根据应用程序的元数据推断的任何缓存。 调用所有 ClearCache 方法后,会为每个指定方法的处理程序调用 UpdateApplication。 可使用 UpdateApplication 来刷新 UI。

示例

以下示例演示了 .NET MAUI 项目的一个场景,该项目最初不支持热重载,但在实现 MetadataUpdateHandler 后又支持该功能。

测试 .NET 热重载

  1. 在 Visual Studio 中创建新的 .NET MAUI 项目。 选择“.NET MAUI 应用”项目模板。

  2. 在 App.xaml.cs 中,将用于创建 MainPage 的代码替换为以下代码:

    //MainPage = new MainPage(); // Template default code
    MainPage = new NavigationPage(new MainPage());
    

    接下来,实现一种生成方法来简化 C# 中的 UI 更新。 此方法会设置 ContentPage.Content 并在页面的 OnNavigatedTo 中调用。 OnNavigatedTo 事件必须托管在 Shell 或 NavigationPage 中。

  3. 在 MainPage.xaml.cs 中,将 MainPage 构造函数代码替换为以下代码:

    public MainPage()
    {
       InitializeComponent();
       Build();
    }
    
    void Build() => Content =
       new Label
       {
          Text = "First line\nSecond line"
       };
    
    protected override void OnNavigatedTo(NavigatedToEventArgs args)
    {
       base.OnNavigatedTo(args);
       Build();
    }
    
  4. 按下 F5 启动该应用。

  5. 加载页面后,将 C# 代码中的标签文本更改为“第一行\n第二行\n第三行”之类的内容

  6. 选择“热重载”Screenshot of the Hot Reload button. 按钮。

    正在运行的应用中不会显示更新后的文本。 默认情况下,此场景不支持热重载。

    Screenshot of Hot Reload not working.

添加 MetadataUpdateHandler

在 .NET MAUI 应用中,在更改代码后,必须执行一些操作来重新运行 C# UI 代码。 如果 UI 代码是用 C# 编写的,可使用 MetadataUpdateHandler 中的 UpdateApplication 方法重新加载 UI。 要进行此设置,请使用以下代码将 HotReloadService.cs 添加到应用程序。

#if DEBUG
[assembly: System.Reflection.Metadata.MetadataUpdateHandlerAttribute(typeof(YourAppNamespace.HotReloadService))]
namespace YourAppNamespace { 
    public static class HotReloadService
    {
        #pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
        public static event Action<Type[]?>? UpdateApplicationEvent;
        #pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

        internal static void ClearCache(Type[]? types) { }
        internal static void UpdateApplication(Type[]? types) {
            UpdateApplicationEvent?.Invoke(types);
        }
    }
}
#endif

请确保将 YourAppNamespace 替换为目标页面的命名空间。

现在,添加上述代码后,在 Visual Studio 中编辑实时代码时,元数据会发生更改,并且应用会调度 UpdateApplicationEvent。 因此,需要添加代码来注册事件并执行 UI 更新。

注意

对于此场景,必须启用 XAML 热重载。

在 MainPage.xaml.cs 中,添加代码以在 OnNavigatedTo 事件中注册 UpdateApplicationEvent 事件处理程序。

protected override void OnNavigatedTo(NavigatedToEventArgs args)
    {
        base.OnNavigatedTo(args);

        Build();

#if DEBUG
        HotReloadService.UpdateApplicationEvent += ReloadUI;
#endif
    }

OnNavigatedFrom 中取消订阅事件处理程序,然后添加代码来处理事件并重新执行对 Build 的调用。

protected override void OnNavigatedFrom(NavigatedFromEventArgs args)
   {
   base.OnNavigatedFrom(args);

#if DEBUG
   HotReloadService.UpdateApplicationEvent -= ReloadUI;
#endif
    }

private void ReloadUI(Type[] obj)
{
   MainThread.BeginInvokeOnMainThread(() =>
   {
      Build();
   });
}

现在启动该应用。 更改 C# 代码中的标签文本并点击“热重载”按钮时,UI 将会刷新!

Screenshot of Hot Reload working.