在源生成器中生成共享代码的正确方法

问题描述 投票:0回答:1

我正在开发一个库,它将使用源生成器来提供用户定义类型的实现。使用要为其生成实现的类型上的属性来提供要为哪种类型生成代码以及如何生成代码。生成的类型将使用一些在每个生成的类型中都相同的委托。在这样的项目中,似乎会生成 3 种代码:

  • 定义稍后将在生成器中使用的属性的代码
  • 定义将在生成的代码的其余部分中重用的类型的代码
  • 定义用户请求的实际类型的代码

根据我对源生成器示例的理解,通过生成用户代码中使用的所有类型来定义它们而不是将它们包含在自己的程序集中是一种常见的做法。

我在理解生成的代码在多项目解决方案中的行为方式时遇到一些问题。假设有 2 个程序集 A 和 B,其中每个程序集都需要我的库来生成一些源代码。在我当前的实现中,两个程序集都将具有所需属性、委托和部分用户类型的定义。

我的问题是,当两个程序集在同一命名空间中具有相同委托的定义时会发生什么(它们应该位于同一命名空间中,因为它们在所有生成的类型中使用)?如果生成了委托,则不会出现编译错误,但如果我在不同的解决方案中定义相同的委托,而它们未生成并包含在单独的程序集中,则会收到错误:CS0101(命名空间“MyNamespace”已包含“我的代表”)。

这让我思考这些类型在不同程序集中生成时是否可以互换。我认为我真正的问题是我是否正确生成了我的源。生成用户程序集需要的所有内容是否正确,还是应该在源生成器库的实际程序集中提供某些类型?

我不确定我上面写的内容是否足以理解以提供答案,但我不知道如何更好地描述它。如果您需要澄清某些事情,请询问。

c# .net-assembly assemblies sourcegenerators
1个回答
0
投票

源生成器生成的代码“只是”一段代码,它遵循您自己编写的所有规则(例如,与编译器不同,它可以生成“无法命名”的标识符)。这意味着您需要使用相应的工具来解决问题。

如果您查看官方的 Source Generators Cookbook 和使用标记属性

INotifyPropertyChanged
实现的示例,那么您会发现这种情况的默认方法是生成内部代码:

[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
sealed class AutoNotifyAttribute : Attribute
{
    public AutoNotifyAttribute()
    {
    }
    public string PropertyName { get; set; }
}

这可能不适用于您的情况,那么您可以考虑其他方法。如果您所依赖的代码实际上并不是“动态”的(即生成的委托始终相同),那么您可以将此类代码移动到共享包/dll 并将其添加到包中。有关此类情况的更详细指导,我建议您查看 Andrew Lock 撰写的解决源生成器“标记属性”问题文章中列出的选项。

它们应该位于相同的命名空间中,因为它们在所有生成的类型中使用

但是这个命名空间可能因项目而异。通过向其添加一些随机 ID 或使用项目根命名空间(在我的项目中没有这样做,但似乎这应该是可能的 - 例如,请参阅如何使用 Roslyn 分析器验证项目属性默认命名空间,也许有还有其他选择)

© www.soinside.com 2019 - 2024. All rights reserved.