我有一个使用反射的工厂,我想用源生成器生成的工厂替换它。
生成的代码应如下所示:
using System;
namespace Generated
{
public static class InsuranceFactory
{
public static IInsurance Get(string insuranceName)
{
switch (insuranceName)
{
case "LifeInsurance":
return new Namespace.LifeInsurance();
case "AutoInsurance":
return new AnotherNamespace.AutoInsurance();
default:
throw new Exception($"Insurance not found for name '{insuranceName}'.");
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用反射,我发现我的类型如下:
List<Type> insuranceTypes = new List<Type>();
Type baseInsuranceType = typeof(IInsurance);
IEnumerable<Assembly> assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(o => !IsFrameworkAssembly(o.FullName ?? String.Empty));
foreach (System.Reflection.Assembly a in assemblies)
{
Type[] types = a.GetTypes();
insuranceTypes.AddRange(types.Where(t => baseInsuranceType.IsAssignableFrom(t) && t.IsClass && !t.IsAbstract && …Run Code Online (Sandbox Code Playgroud) 我正在尝试开发一个源生成器,以使用该接口在部分类上自动实现接口。
我相信这一定是Microsoft 新的 Source Generators 的常见用例,甚至在Roslyn Source Generator Cookbook中被列为用例,但没有示例实现。
我进行了搜索,但很难在 Roslyn 分析器中找到针对此场景的问题。
在说明书中,他们使用 SyntaxReceiver 类来过滤调用应处理哪些语法节点Execute:
class SluggableSyntaxReceiver : ISyntaxReceiver
{
public List<ClassDeclarationSyntax> ClassesToAugment { get; } = new List<ClassDeclarationSyntax>();
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{
// Business logic to decide what we're interested in goes here
if(syntaxNode is ClassDeclarationSyntax cds && cds.HasInterface("IChangeTracked"))
ClassesToAugment.Add(cds)
}
}
Run Code Online (Sandbox Code Playgroud)
查看食谱以了解生成器的实现细节。
我想要确定的是如何HasInterface在 ClassDeclarationSyntax 节点上实现我的扩展。
public static bool HasInterface(this ClassDeclarationSyntax source, string interfaceName)
{
IEnumerable<TypeSyntax> baseTypes = source.BaseList.Types.Select(baseType=>baseType.Type);
// Ideally …Run Code Online (Sandbox Code Playgroud) code-generation roslyn roslyn-code-analysis sourcegenerators
我想发布一个源生成器包,并且我想包含对源生成器项目的私有项目依赖项。
例如,假设我的项目是A.SourceGenerator和A.CodeAnalysis.Core。我想A.SourceGenerator依赖A.CodeAnalysis.Core,但用ProjectReference代替PackageReference。
这意味着我希望在我的A.SourceGenerator.csproj文件中包含以下行或类似的内容:
<None Include="$(OutputPath)\A.CodeAnalysis.Core.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
Run Code Online (Sandbox Code Playgroud)
问题是,这个或一些类似的变体将不起作用,并且会在 CS8785 编译器警告下产生源生成错误,并显示以下错误消息:
生成器BenchmarkSourceGenerator无法生成源。它不会对输出产生影响,因此可能会出现编译错误。
异常类型FileNotFoundException为消息:
无法加载文件或程序集A.CodeAnalysis.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null或其依赖项之一。该系统找不到指定的文件。
显示上述错误是因为项目的内容需要本地复制到源生成器所在的目录上。使用时有一个技巧PackageReference,如此处所示,但它显然不适用于 的情况ProjectReference。
我宁愿避免创建源生成器所依赖的全新 NuGet 包,而只是为了包含依赖项。另一种解决方案是不将其抽象化,并且只有一个源生成器项目包括所有源生成器。
我最近测试了 WPF UI 库 ( https://wpfui.lepo.co/ )。我创建了一个示例项目,该项目针对 .NET 6.0。示例项目包含一些基本的模型和视图模型,在这些文件中我发现使用[ObservableProperty]属性声明的属性。我真的很喜欢它如何减少简单属性所需的代码量,因此我想将其用于面向 .NET Framework 4.7.2 的现有项目。
但我不知道如何或是否可能。我在网上找到的现有信息非常令人困惑,但这个问题的公认答案听起来是可能的:Roslyn Source Generator not generated any source in a .net Framework 4.7.2
我尝试了以下操作,但应用程序无法构建:
using CommunityToolkit.Mvvm.ComponentModel;
namespace MatlogUtility
{
public partial class HeatListEntry : ObservableObject
{
[ObservableProperty]
private int? heatListId;
}
}
Run Code Online (Sandbox Code Playgroud)
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Threading.Tasks;
using System.Windows;
using MatlogUtility.Models;
namespace MatlogUtility
{
public static class SqlQueries
{
public static List<HeatListEntry> GetHeatList()
{
List<HeatListEntry> heatList = new List<HeatListEntry>();
string queryString = …Run Code Online (Sandbox Code Playgroud) 标题几乎解释了这一点。我正在编写一个源生成器,想知道如何查找给定节点的文件路径ClassDeclarationSyntax。这是我希望如何使用它的示例。
IEnumerable<SyntaxNode> allNodes = compilation.SyntaxTrees.SelectMany(s => s.GetRoot().DescendantNodes());
IEnumerable<ClassDeclarationSyntax> allClasses = allNodes.Where(d => d.IsKind(SyntaxKind.ClassDeclaration))
.OfType<ClassDeclarationSyntax>();
IEnumerable<string> filePaths = allClasses.Select(x=> x.GetFilePath());
Run Code Online (Sandbox Code Playgroud) 我开始使用 .NET 5 中的源生成器来生成一些自定义序列化代码。这对于我的用例来说非常有效。不过,我还想以 JSON 文件的形式为所述序列化器创建自定义架构。不幸的是,我无法找到使用源生成器输出所述生成文件的方法。这有可能吗?或者也许我应该使用其他生成方法?
如何将源生成器作为 nuget 包添加到 C# net5 项目?
要将项目添加为源生成器,请使用以下代码完成此工作:
<ItemGroup>
<ProjectReference Include="..\xyz.SourceGenerators\xyz.SourceGenerators.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false"
SetTargetFramework="TargetFramework=netstandard2.0" />
</ItemGroup>
Run Code Online (Sandbox Code Playgroud)
不过,我正在寻找 XMLPackageReference以添加 nuget 包作为源生成器。
我开始使用 C# 源生成器。
我想要的是启动一个git describe --tags --long进程并GitVersion使用当前标签和哈希代码作为属性填充静态类。
问题是,我没有关于引用项目的目录的信息,所以我不知道在哪里运行 git 进程。GeneratorExecutionContext我在函数的参数中找不到任何有用的信息Execute。
AppDomain.CurrentDomain指向 csc.exe 进程,所以我想没有办法知道它在那里?
我正在创建一个 SourceGenerator,它将读取定义流畅 API 的不同状态的 YML 文件,然后生成相关接口来实现语法。
我刚刚看到一条警告,告诉我添加EnforceExtendedAnalyzerRules到我的 csproj,我已经这样做了。现在它告诉我不应该在分析器中执行文件 IO。
我的主要问题是:
我有一个继承自抽象类的基类,但它本身必须声明为partial,因为我正在使用源生成器来生成部分实现。
如何防止partial class在 C# 中实例化它?有没有办法在编译时做到这一点?
编辑:我将 C# 8.0 (.NET Standard 2.1) 与 Xamarin.Forms 项目一起使用。
我试过了partial abstract,但是这是不允许的。
在我的一个项目中,我一直使用一个abstract class作为ViewModel 的基类来实现MVVM 模式。以前,所述基类实现了该INotifyPropertyChanged接口,但现在我切换到CommunityToolkit.Mvvm,以便能够使用MVVM 源生成器 (我已经在其他项目中广泛使用了它,我什至写了一个关于它们的博客系列) 。
显然,在 C# 中,一个类只能是其中之一partial,abstract但不能同时是两者,这是有道理的。由于源生成器仅与类一起使用partial,因此我的基类不能abstract再这样了。但是,这会产生一个问题,即我无法阻止基类在编译时实例化。虽然它仍然是一个abstract class,但无法实例化,但现在可以这样做。
这就是基类过去的样子(简化/修改的示例):
public abstract class ViewModelBase : INotifyPropertyChanged
{
private bool _myBool;
public …Run Code Online (Sandbox Code Playgroud)