Skip to content

Commit

Permalink
[core] use factory methods for registering services
Browse files Browse the repository at this point in the history
In .NET 8 Preview 7, we noticed a regression in startup around:

    .NET 8 Preview 6:
    45.35ms microsoft.maui!Microsoft.Maui.Hosting.MauiAppBuilder.Build()
    .NET 8 Preview 7:
    62.17ms microsoft.maui!Microsoft.Maui.Hosting.MauiAppBuilder.Build()

This may have been related to:

dotnet/runtime#87183

Which should be improved by:

dotnet/runtime#89964

In reviewing the traces, we noticed several places where MAUI was
registering services like:

    services.AddTransient<IFoo, Foo>();

Where we could instead do:

    services.AddTransient<IFoo>(_ => new Foo());

Where this registration avoids any System.Reflection work at startup.
Microsoft.Extensions.DI can just call the factory method instead.

I expanded upon `BannedSymbols.txt` like we did in e7812b0, to ban
cases of `AddTransient` and `AddScoped` that might be used accidentally.

This resulted in banning the slow versions of these APIs like:

    Microsoft.Maui.Hosting.ImageSourceServiceCollectionExtensions.AddService
    Microsoft.Maui.Hosting.MauiHandlersCollectionExtensions.AddHandler
    Microsoft.Maui.Hosting.MauiHandlersCollectionExtensions.TryAddHandler

I also introduced public, fast versions of methods in
`MauiHandlersCollectionExtensions`.

With this change in place, I could see the difference in:

    Before:
    11.24ms microsoft.extensions.dependencyinjection!Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine..ctor
    After:
     6.29ms microsoft.extensions.dependencyinjection!Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine..ctor

Which resulted in an overall faster startup of a `dotnet new maui` app
on a Pixel 5:

    Average(ms): 691
    Std Err(ms): 3.00370142028502
    Std Dev(ms): 9.49853789918334
    Average(ms): 687.8
    Std Err(ms): 4.04365071576553
    Std Dev(ms): 12.7871463239892

This is an average of 10 runs. Note that this was built with main, and
so we have an out-of-date AOT profile compared to the `net8.0` branch.
  • Loading branch information
jonathanpeppers committed Aug 14, 2023
1 parent ff02f57 commit 7406958
Show file tree
Hide file tree
Showing 20 changed files with 221 additions and 89 deletions.
18 changes: 17 additions & 1 deletion eng/BannedSymbols.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,18 @@
M:Microsoft.Extensions.DependencyInjection.Extensions.ServiceCollectionDescriptorExtensions.TryAddSingleton`2(Microsoft.Extensions.DependencyInjection.IServiceCollection);Use a Factory method to create the service instead
M:Android.Content.Res.ColorStateList.#ctor(System.Int32[][],System.Int32[]);Use Microsoft.Maui.PlatformInterop.Get*ColorStateList() Java methods instead
M:Microsoft.Extensions.DependencyInjection.Extensions.ServiceCollectionDescriptorExtensions.TryAddScoped(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Type,System.Type);Use a Factory method to register the service instead
M:Microsoft.Extensions.DependencyInjection.Extensions.ServiceCollectionDescriptorExtensions.TryAddScoped`2(Microsoft.Extensions.DependencyInjection.IServiceCollection);Use a Factory method to register the service instead
M:Microsoft.Extensions.DependencyInjection.Extensions.ServiceCollectionDescriptorExtensions.TryAddSingleton(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Type,System.Type);Use a Factory method to register the service instead
M:Microsoft.Extensions.DependencyInjection.Extensions.ServiceCollectionDescriptorExtensions.TryAddSingleton`2(Microsoft.Extensions.DependencyInjection.IServiceCollection);Use a Factory method to register the service instead
M:Microsoft.Extensions.DependencyInjection.Extensions.ServiceCollectionDescriptorExtensions.TryAddTransient(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Type,System.Type);Use a Factory method to register the service instead
M:Microsoft.Extensions.DependencyInjection.Extensions.ServiceCollectionDescriptorExtensions.TryAddTransient`2(Microsoft.Extensions.DependencyInjection.IServiceCollection);Use a Factory method to register the service instead
M:Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddScoped(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Type,System.Type);Use a Factory method to register the service instead
M:Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddScoped`2(Microsoft.Extensions.DependencyInjection.IServiceCollection);Use a Factory method to register the service instead
M:Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Type,System.Type);Use a Factory method to register the service instead
M:Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton`2(Microsoft.Extensions.DependencyInjection.IServiceCollection);Use a Factory method to register the service instead
M:Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddTransient(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Type,System.Type);Use a Factory method to register the service instead
M:Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddTransient`2(Microsoft.Extensions.DependencyInjection.IServiceCollection);Use a Factory method to register the service instead
M:Microsoft.Maui.Hosting.ImageSourceServiceCollectionExtensions.AddService`2(Microsoft.Maui.Hosting.IImageSourceServiceCollection);Use a Factory method to register the service instead
M:Microsoft.Maui.Hosting.MauiHandlersCollectionExtensions.AddHandler(Microsoft.Maui.Hosting.IMauiHandlersCollection,System.Type,System.Type);Use a Factory method to register the service instead
M:Microsoft.Maui.Hosting.MauiHandlersCollectionExtensions.AddHandler`2(Microsoft.Maui.Hosting.IMauiHandlersCollection);Use a Factory method to register the service instead
M:Microsoft.Maui.Hosting.MauiHandlersCollectionExtensions.TryAddHandler(Microsoft.Maui.Hosting.IMauiHandlersCollection,System.Type,System.Type);Use a Factory method to register the service instead
M:Microsoft.Maui.Hosting.MauiHandlersCollectionExtensions.TryAddHandler`2(Microsoft.Maui.Hosting.IMauiHandlersCollection);Use a Factory method to register the service instead
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public static IMauiBlazorWebViewBuilder AddMauiBlazorWebView(this IServiceCollec
services.TryAddSingleton(new BlazorWebViewDeveloperTools { Enabled = false });
#if WEBVIEW2_MAUI
services.TryAddSingleton<MauiBlazorMarkerService>();
services.ConfigureMauiHandlers(static handlers => handlers.AddHandler<IBlazorWebView, BlazorWebViewHandler>());
services.ConfigureMauiHandlers(static handlers => handlers.AddHandler<IBlazorWebView>(_ => new BlazorWebViewHandler()));
return new MauiBlazorWebViewBuilder(services);
#elif WEBVIEW2_WINFORMS
services.TryAddSingleton<WindowsFormsBlazorMarkerService>();
Expand Down
16 changes: 8 additions & 8 deletions src/Compatibility/Core/src/MauiHandlersCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ public static IMauiHandlersCollection TryAddCompatibilityRenderer(this IMauiHand
Internals.Registrar.Registered.Register(controlType, rendererType);

#if PLATFORM
#pragma warning disable CS0612 // Type or member is obsolete
#pragma warning disable CS0612, RS0030 // Type or member is obsolete
handlersCollection.TryAddHandler(controlType, typeof(RendererToHandlerShim));
#pragma warning restore CS0612 // Type or member is obsolete
#pragma warning restore CS0612, RS0030 // Type or member is obsolete
#endif

return handlersCollection;
Expand All @@ -28,9 +28,9 @@ public static IMauiHandlersCollection AddCompatibilityRenderer(this IMauiHandler
Internals.Registrar.Registered.Register(controlType, rendererType);

#if PLATFORM
#pragma warning disable CS0612 // Type or member is obsolete
#pragma warning disable CS0612, RS0030 // Type or member is obsolete
handlersCollection.AddHandler(controlType, typeof(RendererToHandlerShim));
#pragma warning restore CS0612 // Type or member is obsolete
#pragma warning restore CS0612, RS0030 // Type or member is obsolete
#endif

return handlersCollection;
Expand All @@ -44,9 +44,9 @@ public static IMauiHandlersCollection AddCompatibilityRenderer<TControlType, TMa
Internals.Registrar.Registered.Register(typeof(TControlType), typeof(TRenderer));

#if PLATFORM
#pragma warning disable CS0612 // Type or member is obsolete
#pragma warning disable CS0612, RS0030 // Type or member is obsolete
handlersCollection.AddHandler<TMauiType, RendererToHandlerShim>();
#pragma warning restore CS0612 // Type or member is obsolete
#pragma warning restore CS0612, RS0030 // Type or member is obsolete
#endif
return handlersCollection;
}
Expand Down Expand Up @@ -76,9 +76,9 @@ public static IMauiHandlersCollection AddCompatibilityRenderers(this IMauiHandle
}, default(InitializationFlags),
(result) =>
{
#pragma warning disable CS0612 // Type or member is obsolete
#pragma warning disable CS0612, RS0030 // Type or member is obsolete
handlersCollection?.TryAddHandler(result.target, typeof(RendererToHandlerShim));
#pragma warning restore CS0612 // Type or member is obsolete
#pragma warning restore CS0612, RS0030 // Type or member is obsolete
});
#endif

Expand Down
6 changes: 3 additions & 3 deletions src/Controls/Maps/src/AppHostBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ public static MauiAppBuilder UseMauiMaps(this MauiAppBuilder builder)
public static IMauiHandlersCollection AddMauiMaps(this IMauiHandlersCollection handlersCollection)
{
#if __ANDROID__ || __IOS__
handlersCollection.AddHandler<Map, MapHandler>();
handlersCollection.AddHandler<Pin, MapPinHandler>();
handlersCollection.AddHandler<MapElement, MapElementHandler>();
handlersCollection.AddHandler<Map>(_ => new MapHandler());
handlersCollection.AddHandler<Pin>(_ => new MapPinHandler());
handlersCollection.AddHandler<MapElement>(_ => new MapElementHandler());
#endif
return handlersCollection;
}
Expand Down
153 changes: 82 additions & 71 deletions src/Controls/src/Xaml/Hosting/AppHostBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,101 +62,112 @@ public static partial class AppHostBuilderExtensions

public static IMauiHandlersCollection AddMauiControlsHandlers(this IMauiHandlersCollection handlersCollection)
{
handlersCollection.AddHandler<CollectionView, CollectionViewHandler>();
handlersCollection.AddHandler<CarouselView, CarouselViewHandler>();
handlersCollection.AddHandler<Application, ApplicationHandler>();
handlersCollection.AddHandler<ActivityIndicator, ActivityIndicatorHandler>();
handlersCollection.AddHandler<BoxView, BoxViewHandler>();
handlersCollection.AddHandler<Button, ButtonHandler>();
handlersCollection.AddHandler<CheckBox, CheckBoxHandler>();
handlersCollection.AddHandler<DatePicker, DatePickerHandler>();
handlersCollection.AddHandler<Editor, EditorHandler>();
handlersCollection.AddHandler<Entry, EntryHandler>();
handlersCollection.AddHandler<GraphicsView, GraphicsViewHandler>();
handlersCollection.AddHandler<Image, ImageHandler>();
handlersCollection.AddHandler<Label, LabelHandler>();
handlersCollection.AddHandler<Layout, LayoutHandler>();
handlersCollection.AddHandler<Picker, PickerHandler>();
handlersCollection.AddHandler<ProgressBar, ProgressBarHandler>();
handlersCollection.AddHandler<ScrollView, ScrollViewHandler>();
handlersCollection.AddHandler<SearchBar, SearchBarHandler>();
handlersCollection.AddHandler<Slider, SliderHandler>();
handlersCollection.AddHandler<Stepper, StepperHandler>();
handlersCollection.AddHandler<Switch, SwitchHandler>();
handlersCollection.AddHandler<TimePicker, TimePickerHandler>();
handlersCollection.AddHandler<Page, PageHandler>();
handlersCollection.AddHandler<WebView, WebViewHandler>();
handlersCollection.AddHandler<Border, BorderHandler>();
handlersCollection.AddHandler<IContentView, ContentViewHandler>();
handlersCollection.AddHandler<Shapes.Ellipse, ShapeViewHandler>();
handlersCollection.AddHandler<Shapes.Line, LineHandler>();
handlersCollection.AddHandler<Shapes.Path, PathHandler>();
handlersCollection.AddHandler<Shapes.Polygon, PolygonHandler>();
handlersCollection.AddHandler<Shapes.Polyline, PolylineHandler>();
handlersCollection.AddHandler<Shapes.Rectangle, RectangleHandler>();
handlersCollection.AddHandler<Shapes.RoundRectangle, RoundRectangleHandler>();
handlersCollection.AddHandler<Window, WindowHandler>();
handlersCollection.AddHandler<ImageButton, ImageButtonHandler>();
handlersCollection.AddHandler<IndicatorView, IndicatorViewHandler>();
handlersCollection.AddHandler<RadioButton, RadioButtonHandler>();
handlersCollection.AddHandler<RefreshView, RefreshViewHandler>();
handlersCollection.AddHandler<SwipeItem, SwipeItemMenuItemHandler>();
handlersCollection.AddHandler<SwipeView, SwipeViewHandler>();
handlersCollection.AddHandler<CollectionView>(_ => new CollectionViewHandler());
handlersCollection.AddHandler<CarouselView>(_ => new CarouselViewHandler());
handlersCollection.AddHandler<Application>(_ => new ApplicationHandler());
handlersCollection.AddHandler<ActivityIndicator>(_ => new ActivityIndicatorHandler());
handlersCollection.AddHandler<BoxView>(_ => new BoxViewHandler());
handlersCollection.AddHandler<Button>(_ => new ButtonHandler());
handlersCollection.AddHandler<CheckBox>(_ => new CheckBoxHandler());
handlersCollection.AddHandler<DatePicker>(_ => new DatePickerHandler());
handlersCollection.AddHandler<Editor>(_ => new EditorHandler());
handlersCollection.AddHandler<Entry>(_ => new EntryHandler());
handlersCollection.AddHandler<GraphicsView>(_ => new GraphicsViewHandler());
handlersCollection.AddHandler<Image>(_ => new ImageHandler());
handlersCollection.AddHandler<Label>(_ => new LabelHandler());
handlersCollection.AddHandler<Layout>(_ => new LayoutHandler());
handlersCollection.AddHandler<Picker>(_ => new PickerHandler());
handlersCollection.AddHandler<ProgressBar>(_ => new ProgressBarHandler());
handlersCollection.AddHandler<ScrollView>(_ => new ScrollViewHandler());
handlersCollection.AddHandler<SearchBar>(_ => new SearchBarHandler());
handlersCollection.AddHandler<Slider>(_ => new SliderHandler());
handlersCollection.AddHandler<Stepper>(_ => new StepperHandler());
handlersCollection.AddHandler<Switch>(_ => new SwitchHandler());
handlersCollection.AddHandler<TimePicker>(_ => new TimePickerHandler());
handlersCollection.AddHandler<Page>(_ => new PageHandler());
handlersCollection.AddHandler<WebView>(_ => new WebViewHandler());
handlersCollection.AddHandler<Border>(_ => new BorderHandler());
handlersCollection.AddHandler<IContentView>(_ => new ContentViewHandler());
handlersCollection.AddHandler<Shapes.Ellipse>(_ => new ShapeViewHandler());
handlersCollection.AddHandler<Shapes.Line>(_ => new LineHandler());
handlersCollection.AddHandler<Shapes.Path>(_ => new PathHandler());
handlersCollection.AddHandler<Shapes.Polygon>(_ => new PolygonHandler());
handlersCollection.AddHandler<Shapes.Polyline>(_ => new PolylineHandler());
handlersCollection.AddHandler<Shapes.Rectangle>(_ => new RectangleHandler());
handlersCollection.AddHandler<Shapes.RoundRectangle>(_ => new RoundRectangleHandler());
handlersCollection.AddHandler<Window>(_ => new WindowHandler());
handlersCollection.AddHandler<ImageButton>(_ => new ImageButtonHandler());
handlersCollection.AddHandler<IndicatorView>(_ => new IndicatorViewHandler());
handlersCollection.AddHandler<RadioButton>(_ => new RadioButtonHandler());
handlersCollection.AddHandler<RefreshView>(_ => new RefreshViewHandler());
handlersCollection.AddHandler<SwipeItem>(_ => new SwipeItemMenuItemHandler());
handlersCollection.AddHandler<SwipeView>(_ => new SwipeViewHandler());

#pragma warning disable CA1416 // 'MenuBarHandler', MenuFlyoutSubItemHandler, MenuFlyoutSubItemHandler, MenuBarItemHandler is only supported on: 'ios' 13.0 and later
handlersCollection.AddHandler<MenuBar, MenuBarHandler>();
handlersCollection.AddHandler<MenuFlyoutSubItem, MenuFlyoutSubItemHandler>();
handlersCollection.AddHandler<MenuFlyoutSeparator, MenuFlyoutSeparatorHandler>();
handlersCollection.AddHandler<MenuFlyoutItem, MenuFlyoutItemHandler>();
handlersCollection.AddHandler<MenuBarItem, MenuBarItemHandler>();
handlersCollection.AddHandler<MenuBar>(_ => new MenuBarHandler());
handlersCollection.AddHandler<MenuFlyoutSubItem>(_ => new MenuFlyoutSubItemHandler());
handlersCollection.AddHandler<MenuFlyoutSeparator>(_ => new MenuFlyoutSeparatorHandler());
handlersCollection.AddHandler<MenuFlyoutItem>(_ => new MenuFlyoutItemHandler());
handlersCollection.AddHandler<MenuBarItem>(_ => new MenuBarItemHandler());
#pragma warning restore CA1416

#if WINDOWS || ANDROID || IOS || MACCATALYST || TIZEN
handlersCollection.AddHandler(typeof(ListView), typeof(Handlers.Compatibility.ListViewRenderer));
handlersCollection.AddHandler<ListView>(svc => new Handlers.Compatibility.ListViewRenderer(
#if ANDROID
svc.GetRequiredService<Android.Content.Context>()
#endif
));
#if !TIZEN
handlersCollection.AddHandler(typeof(Cell), typeof(Handlers.Compatibility.CellRenderer));
handlersCollection.AddHandler(typeof(ImageCell), typeof(Handlers.Compatibility.ImageCellRenderer));
handlersCollection.AddHandler(typeof(EntryCell), typeof(Handlers.Compatibility.EntryCellRenderer));
handlersCollection.AddHandler(typeof(TextCell), typeof(Handlers.Compatibility.TextCellRenderer));
handlersCollection.AddHandler(typeof(ViewCell), typeof(Handlers.Compatibility.ViewCellRenderer));
handlersCollection.AddHandler(typeof(SwitchCell), typeof(Handlers.Compatibility.SwitchCellRenderer));
handlersCollection.AddHandler<ImageCell>(_ => new Handlers.Compatibility.ImageCellRenderer());
handlersCollection.AddHandler<EntryCell>(_ => new Handlers.Compatibility.EntryCellRenderer());
handlersCollection.AddHandler<TextCell>(_ => new Handlers.Compatibility.TextCellRenderer());
handlersCollection.AddHandler<ViewCell>(_ => new Handlers.Compatibility.ViewCellRenderer());
handlersCollection.AddHandler<SwitchCell>(_ => new Handlers.Compatibility.SwitchCellRenderer());
#endif
handlersCollection.AddHandler(typeof(TableView), typeof(Handlers.Compatibility.TableViewRenderer));
handlersCollection.AddHandler(typeof(Frame), typeof(Handlers.Compatibility.FrameRenderer));
handlersCollection.AddHandler<TableView>(svc => new Handlers.Compatibility.TableViewRenderer(
#if ANDROID
svc.GetRequiredService<Android.Content.Context>()
#endif
));
handlersCollection.AddHandler<Frame>(svc => new Handlers.Compatibility.FrameRenderer(
#if ANDROID
svc.GetRequiredService<Android.Content.Context>()
#endif
));
#endif

#if WINDOWS || MACCATALYST
handlersCollection.AddHandler(typeof(MenuFlyout), typeof(MenuFlyoutHandler));
handlersCollection.AddHandler<MenuFlyout>(_ => new MenuFlyoutHandler());
#endif

#if IOS || MACCATALYST
handlersCollection.AddHandler(typeof(NavigationPage), typeof(Handlers.Compatibility.NavigationRenderer));
handlersCollection.AddHandler(typeof(TabbedPage), typeof(Handlers.Compatibility.TabbedRenderer));
handlersCollection.AddHandler(typeof(FlyoutPage), typeof(Handlers.Compatibility.PhoneFlyoutPageRenderer));
handlersCollection.AddHandler<NavigationPage>(_ => new Handlers.Compatibility.NavigationRenderer());
handlersCollection.AddHandler<TabbedPage>(_ => new Handlers.Compatibility.TabbedRenderer());
handlersCollection.AddHandler<FlyoutPage>(_ => new Handlers.Compatibility.PhoneFlyoutPageRenderer());
#endif

#if ANDROID || IOS || MACCATALYST || TIZEN
handlersCollection.AddHandler<SwipeItemView, SwipeItemViewHandler>();
handlersCollection.AddHandler<SwipeItemView>(_ => new SwipeItemViewHandler());
#if ANDROID || IOS || MACCATALYST
handlersCollection.AddHandler<Shell, ShellRenderer>();
handlersCollection.AddHandler<Shell>(_ => new ShellRenderer());
#else
handlersCollection.AddHandler<Shell, ShellHandler>();
handlersCollection.AddHandler<ShellItem, ShellItemHandler>();
handlersCollection.AddHandler<ShellSection, ShellSectionHandler>();
handlersCollection.AddHandler<Shell>(_ => new ShellHandler());
handlersCollection.AddHandler<ShellItem>(_ => new ShellItemHandler());
handlersCollection.AddHandler<ShellSection>(_ => new ShellSectionHandler());
#endif
#endif
#if WINDOWS || ANDROID || TIZEN
handlersCollection.AddHandler<NavigationPage, NavigationViewHandler>();
handlersCollection.AddHandler<Toolbar, ToolbarHandler>();
handlersCollection.AddHandler<FlyoutPage, FlyoutViewHandler>();
handlersCollection.AddHandler<TabbedPage, TabbedViewHandler>();
handlersCollection.AddHandler<NavigationPage>(_ => new NavigationViewHandler());
handlersCollection.AddHandler<Toolbar>(_ => new ToolbarHandler());
handlersCollection.AddHandler<FlyoutPage>(_ => new FlyoutViewHandler());
handlersCollection.AddHandler<TabbedPage>(_ => new TabbedViewHandler());
#endif

#if WINDOWS
handlersCollection.AddHandler<ShellItem, ShellItemHandler>();
handlersCollection.AddHandler<ShellSection, ShellSectionHandler>();
handlersCollection.AddHandler<ShellContent, ShellContentHandler>();
handlersCollection.AddHandler<Shell, ShellHandler>();
handlersCollection.AddHandler<ShellItem>(_ => new ShellItemHandler());
handlersCollection.AddHandler<ShellSection>(_ => new ShellSectionHandler());
handlersCollection.AddHandler<ShellContent>(_ => new ShellContentHandler());
handlersCollection.AddHandler<Shell>(_ => new ShellHandler());
#endif
return handlersCollection;
}
Expand Down
1 change: 1 addition & 0 deletions src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<NoWarn>$(NoWarn),CA1416</NoWarn>
<!-- Disable multi-RID builds to workaround a parallel build issue -->
<RuntimeIdentifier Condition="$(TargetFramework.Contains('-maccatalyst'))">maccatalyst-x64</RuntimeIdentifier>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<PropertyGroup>
Expand Down
Loading

0 comments on commit 7406958

Please sign in to comment.