Source Generator 與 EmbeddedAttribute

  • 120
  • 0

使用 EmbeddedAttribute 處理一個罕見的情境。

假設有三個專案,專案結構如下:

Solution/
├── ProjectA (類別庫)
│   └── 引用 MySourceGenerator NuGet 套件
└── ProjectB (主程式)
    └── 引用 ProjectA
    └── 引用 MySourceGenerator NuGet 套件

其中 source generator 的 PostInitializationOutput 輸出一個公開的 Attribute

 private static void PostInitializationOutput(IncrementalGeneratorPostInitializationContext context)
 {         
     context.AddSource("TestAttribute.g.cs", """
        using System;
        namespace Embbeded.Test;  
        public class TestAttribute : Attribute {}
        """);               
 }

由於  ProjectA 和 ProjectB 都引用了 MySourceGenerator,所以在兩個專案中都會生成 TestAttribute;而 ProjectB 偏偏又引用了 ProjectA,於是就出現了兩個一模一樣的 TestAttribute。這個現象其實很罕見,在一般的情況下,其實把 TestAttribute 的存取修飾設定為 internal 就沒有問題,但是如果存取修飾非得是 public 或是有 InternalVisibleTo 的情況  ,就會出現 CS0436 的警告。

要解除這個警告的方式就是應用 EmbeddedAttribute,使用這個標籤需要兩道程序。

  1. 呼叫 IncrementalGeneratorPostInitializationContext.AddEmbeddedAttributeDefinition
  2. 在輸出的程式碼上掛上 EmbeddedAttribute

所以 PostInitializationOutput 修改成以下,就會解除這個警告

 private static void PostInitializationOutput(IncrementalGeneratorPostInitializationContext context)
 {
     context.AddEmbeddedAttributeDefinition();
     context.AddSource("TestAttribute.g.cs", """
        using System;
        using Microsoft.CodeAnalysis;
        namespace Embbeded.Test;                 
        [Embedded]
        public class TestAttribute : Attribute {}
        """);
 }

不過這個情境的確非常罕見,大概用到的機會也不太多,只是隨手記錄一下有這玩意而已。