問題の発見#
最近、Avalonia プログラムを作成している際に、デバッグ時は正常に動作するのに、リリース後は実行できないことに気づき、非常に奇妙に感じました。私のリリース設定には以下の 2 つがあります:
<PublishTrimmed>True</PublishTrimmed>
<PublishAot Condition="'$(Configuration)' != 'Debug'">true</PublishAot>
最初の行はトリミングを有効にし、2 番目の行は AOT コンパイルを有効にしています(ただし、開発時には AOT が有効になっていません。プレビューウィンドウが AOT をサポートしていないためです)。
いくつかの調査の結果、これら 2 つに問題があることがわかりました:
- 反射は AOT に対して不利です。私の
ViewLocator.cs
はオブジェクトを作成するために反射を使用しています。 - 一部のライブラリはトリミングのサポートが不十分であるため、トリミングを無効にする必要があります。
解決策#
問題 1: 反射の排除#
元のコードは反射を使用してオブジェクトを作成していました:
public Control? Build(object? param)
{
if (param != null && param is ViewModelBase)
{
var viewModelType = param.GetType();
if (_viewModelViewMappings.TryGetValue(viewModelType, out var viewType))
{
return (Control)Activator.CreateInstance(viewType)!; // ここで反射を使用
}
return new TextBlock { Text = "Not Found: " + viewModelType.FullName };
}
return null;
}
修正後はファクトリメソッドを使用します:
public Control? Build(object? param)
{
if (param != null && param is ViewModelBase)
{
var viewModelType = param.GetType();
if (_viewModelViewMappings.TryGetValue(viewModelType, out var viewFactory))
{
return viewFactory(); // ファクトリメソッドを使用
}
return new TextBlock { Text = "Not Found: " + viewModelType.FullName };
}
return null;
}
これにより、反射を排除できます。
問題 2: 特定のライブラリのトリミングを無効にする#
リリース時に、多くのトリミング警告に気づきました。
2>Assembly 'Serilog' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
2>Assembly 'ReactiveUI' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
2>Assembly 'SukiUI' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
2>Assembly 'Avalonia.Controls.DataGrid' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
2>Assembly 'Avalonia.Controls.DataGrid' produced AOT analysis warnings.
そのため、プロジェクトの sln ファイルを修正し、以下のスニペットを追加して、外部の xml ファイルを通じてトリミングを制限しました。
<ItemGroup>
<TrimmerRootDescriptor Include="TrimmerRoots.xml" />
</ItemGroup>
以下はTrimmerRoots.xml
の内容です。
<?xml version="1.0" encoding="utf-8" ?>
<linker>
<assembly fullname="Serilog" />
<assembly fullname="Serilog.Sinks.Console" />
<assembly fullname="Serilog.Sinks.File" />
<assembly fullname="ReactiveUI" />
<assembly fullname="SukiUI" />
<assembly fullname="Serilog.Sinks.File" />
</linker>
私はすべての警告が出たプロジェクトを追加しましたが、その後のコンパイルでも新しい警告が出続けました。しかし、プログラムは正常に実行できるようになりました。これで、すべての問題が解決しました。