在使用默认的 WPF 项目开发的时候,咱是不需要自己编写 Main 函数的,在 WPF 中的 Main 函数是存放在 App.g.cs 里面,看起来这个 Main 函数是生成的函数,本文将介绍在 WPF 框架中是如何创建这个入口函数
阅读本文你将了解 WPF 框架中,默认在 App.g.cs 生成入口 Main 函数的详细过程。阅读本文之前,你需要了解一些编译过程的知识以及代码生成的知识
默认的 Application 继承类命名是 App.xaml 如果在你的项目中,依然使用默认的命名,那么在 .NET 5 的 SDK 下,将会自动加上以下默认的代码
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
上面代码是将 App.xaml 识别作为 ApplicationDefinition 的特殊内容,这个内容将被作为创建入口函数的出发点文件。也就是 App.g.cs 文件里面存放入口函数就由此决定
在 src\Microsoft.DotNet.Wpf\src\PresentationBuildTasks\MS\Internal\MarkupCompiler\MarkupCompiler.cs
文件里面的 GenerateAppEntryPoint 函数,如此函数命名所示,这就是创建应用入口点的方法,大概逻辑如下
private void GenerateAppEntryPoint()
{
if (ApplicationFile.Length > 0)
{
// [STAThread]
// public static void Main ()
//
CodeMemberMethod cmmMain = GenerateEntryPointMethod();
if (cmmMain != null)
{
// SplashScreen splashScreen = new SplashScreen("SplashScreen.png");
//
CodeVariableReferenceExpression cvreSplashScreen = null;
if (!string.IsNullOrEmpty(_splashImage) && !HostInBrowser)
{
cvreSplashScreen = GenerateSplashScreenInstance(cmmMain);
}
// MyApplication app = new MyApplication();
//
CodeVariableReferenceExpression cvreApp = GenerateAppInstance(cmmMain);
if (_ccRoot.InitializeComponentFn != null)
{
// app.InitializeComponent();
//
CodeMethodInvokeExpression cmieIT = new CodeMethodInvokeExpression();
cmieIT.Method = new CodeMethodReferenceExpression(cvreApp, INITIALIZE_COMPONENT);
cmmMain.Statements.Add(new CodeExpressionStatement(cmieIT));
}
if (!HostInBrowser)
{
// app.Run();
//
CodeMethodReferenceExpression cmreRun = new CodeMethodReferenceExpression(cvreApp, "Run");
CodeMethodInvokeExpression cmieRun = new CodeMethodInvokeExpression();
cmieRun.Method = cmreRun;
CodeStatement csRun = new CodeExpressionStatement(cmieRun);
cmmMain.Statements.Add(csRun);
}
_ccRoot.CodeClass.Members.Add(cmmMain);
}
}
}
在 WPF 中不是拼接字符串的方式完成代码生成的,而是需要用上代码生成逻辑进行生成。在上面代码中有各个注释来告诉大家生成代码的作用,阅读方便
调用链关系上,通过 Roslyn 如何了解某个项目在 msbuild 中所有用到的属性以及构建过程 的方法,可以看到在构建过程中,将会先使用 UsingTask 加载 MarkupCompilePass2 任务
<UsingTask TaskName="Microsoft.Build.Tasks.Windows.MarkupCompilePass2" A