Having previously written aSource Generator generates code for automatic injection Mainly throughSyntaxProvider
Find Annotation Feature Implementation
In fact, apart fromSyntaxProvider
There are several other important Providers, such as.MetadataReferencesProvider
,AdditionalTextsProvider
,AnalyzerConfigOptionsProvider
etc.
Today.AnalyzerConfigOptionsProvider
This Provider, here, gets references to project folders and top-level namespaces through the AnalyzerConfigOptionsProvider.
With the following code we can print out the referenced project'sGlobalOptions
:
var projectKeysProvider =
.Select((options, _) =>
{
var keys = ;
List<(string? Key, string? Value)> keyValues = [];
foreach (var key in keys)
{
(key, out var value);
((key, value));
}
return keyValues;
});
(projectKeysProvider, (ctx, projectKeys) =>
{
// Generate Code
StringBuilder stringBuilder = new();
foreach (var (Key, Value) in projectKeys)
{
($"// {Key} {Value}");
}
});
It's not hard to see that the key for the project folder and the top-level namespace isbuild_property.projectdir
,build_property.rootnamespace
,
Once we have the project folder address we can read the corresponding*.csproj
project file. Here we read the file via IO and fetch the configuredAssemblyVersion
,FileVersion
,Version
item, and then you can generate the version information.
The project file itself is an Xml file, so reading the configuration items can be done using theXPath
orregular expression (math.)
For the sake of simplicity and efficiency, here's the regular expression I'm using to get.
//Generate version number
var inc = ((pvd, _) =>
{
//Access to project catalogs
var flag = ("build_property.projectdir", out var root);
if (!flag)
return new VersionInfo(null, null);
//Acquisition of namespace
("build_property.rootnamespace", out var @namespace);
//var file = (root, $"*.csproj");
//findcsprojfile
var files = (root, "*.csproj", );
return new VersionInfo(@namespace, == 0 ? null : files[0]);
});
//generating
(inc, (ctx, info) =>
{
if ( == null || == null)
return;
string version = DefaultVersion;
string fileVersion = DefaultVersion;
string assemblyVersion = DefaultVersion;
// 获取不含扩展名的file名
//var @namespace = (info.Item2);
// 读取file
var text = ();
// go down (in history)Import的file,for example : <Import Project="..\" />
// Matching with regular expressionsProject:
var importMatchs = (text, "<Import Project=\"(.*?)\"");
foreach (Match importMatch in importMatchs)
{
var importFile = ((), [1].Value);
if ((importFile))
{
text += (importFile);
}
}
var match = (text, "<Version>(.*?)</Version>");
var fileVersionMatch = (text, "<FileVersion>(.*?)</FileVersion>");
var assemblyVersionMatch = (text, "<AssemblyVersion>(.*?)</AssemblyVersion>");
if ()
{
version = [1].Value;
}
if ()
{
fileVersion = [1].Value;
}
if ()
{
assemblyVersion = [1].Value;
}
string source = $@"// <auto-generated/>
namespace {}.Generated
{{
/// <summary>
/// The version class
/// </summary>
public static class Version
{{
/// <summary>
/// The current version
/// </summary>
public static Current => (""{version}"");
/// <summary>
/// The file version
/// </summary>
public static FileVersion => (""{fileVersion}"");
/// <summary>
/// The assembly version
/// </summary>
public static AssemblyVersion => (""{assemblyVersion}"");
}}
}}
";
// output code
("", (source, Encoding.UTF8));
});
Then the desired content was generated:
// <auto-generated/>
namespace
{
/// <summary>
/// The version class
/// </summary>
public static class Version
{
/// <summary>
/// The current version
/// </summary>
public static Current => ("2.0.0");
/// <summary>
/// The file version
/// </summary>
public static FileVersion => ("2.0.0");
/// <summary>
/// The assembly version
/// </summary>
public static AssemblyVersion => ("2.0.0");
}
}
lastly{namespace}..*
You can get the version information
With the above code we can theoretically read the contents of all the files in the project folder, except of course theAnalyzerConfigOptionsProvider
In addition, we can also use theAdditionalTextsProvider
Read the contents of the attached file, since the current article does not cover it I'll talk about it sometime!
The above code completes the entire source generation step, and finally you can use the nuget package I released to experience.
dotnet add package
I posted the source code to GitHub, welcome to star!/vipwan/
/vipwan//blob/master//