我计划在 Unity 项目中使用自定义 Roslyn 代码生成器。
我找到了有关如何使用 正确设置代码生成器的信息CodeGeneration.Roslyn。通过此设置,可以轻松将代码生成器导出为 NuGet 包并将其导入到任何其他项目中。
第一个问题是通过这样的 NuGet 包生成代码是否可以在Unity 2020.2 LTS下工作。我想知道在 Unity 项目中实现如下所示的 MSBuild 项目引用有多麻烦。我想避免自己尝试这个,因为它可能根本不起作用,但在等待答案时我无论如何都会这样做:
<ItemGroup>
<PackageReference Include="CodeGeneration.Roslyn.Tool" Version="0.7.63">
<IncludeAssets>runtime; build; native; contentfiles; analyzers;buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<!-- This ProjectReference to the generator needs to have the OutputItemType metadata -->
<ProjectReference Include="..\Duplicator.Generators\Duplicator.Generators.csproj"
ReferenceOutputAssembly="false"
SetTargetFramework="TargetFramework=net4.7.2"
OutputItemType="CodeGenerationRoslynPlugin" />
<ProjectReference Include="..\Duplicator.Attributes\Duplicator.Attributes.csproj"
ExcludeAssets="runtime"
SetTargetFramework="TargetFramework=net4.7.2"
PrivateAssets="all" />
</ItemGroup>
Run Code Online (Sandbox Code Playgroud)
这种方法的问题是代码生成器将不在 Unity 项目内。NuGet 导出间接性将使调试生成器变得更加困难。
因此,第二个想法是 …
所以我的代码中有一个已知的属性类型,例如:
[AttributeUsage(AttributeTargets.Method)]
public class AliasAttribute : Attribute
{
public string Alias;
public AliasAttribute(string alias)
{
Alias = alias;
}
}
Run Code Online (Sandbox Code Playgroud)
我还有一个用这个属性装饰的方法,我IMethodSymbol在 Roslyn 中得到了它:
// E.g. code which Roslyn gets to analyze
[Alias("Hello")] public void World() {}
// Actual Roslyn code
var method = (IMethodSymbol) compilation.GetSymbolsWithName("World").Single();
Run Code Online (Sandbox Code Playgroud)
我可以使用与此类似的代码检索属性数据:
var attributeData = method.GetAttributes().Single();
Run Code Online (Sandbox Code Playgroud)
现在我想使用一些简单的内置方法将其转换AttributeData为已知类型,例如如下所示:
AliasAttribute alias = attributeData.MapToType<AliasAttribute>();
Run Code Online (Sandbox Code Playgroud)
我目前的做法很复杂:它涉及使用反射实例化属性类型。然而,我没有考虑到很多边缘情况,比如params通用方式的参数。请参阅下面答案中的代码。但是,它太复杂了,我想知道是否有更简单的方法来做到这一点。