C#如何通过继承重载运算符实现突变测试(无需修改业务类)
问题解决:通过继承基类替换业务类中的加法为减法
首先,你遇到的编译器错误是因为C#运算符重载的语法规则限制:定义二元运算符时,必须有一个参数属于包含该运算符的类型。你在Mutator中重载int + int,但Mutator和int无继承或包含关系,因此这种写法本身不合法,无法直接实现。
下面提供两种无需修改业务类代码的可行方案:
方案一:运行时IL拦截(动态代理)
利用动态代理框架(如Castle DynamicProxy)拦截业务类的方法执行,在运行时修改逻辑,将加法操作替换为减法。
实现步骤:
- 引入
Castle.CoreNuGet包 - 编写
Mutator基类和拦截器:
using Castle.DynamicProxy; public class Mutator { protected Mutator() { // 构造时自动生成代理实例 var proxyGenerator = new ProxyGenerator(); var proxy = proxyGenerator.CreateClassProxy(GetType(), new AddToSubtractInterceptor()); // 将代理的属性复制到当前实例 CopyProxyMembers(proxy, this); } private void CopyProxyMembers(object proxy, object target) { foreach (var prop in proxy.GetType().GetProperties()) { if (prop.CanRead && prop.CanWrite) prop.SetValue(target, prop.GetValue(proxy)); } foreach (var field in proxy.GetType().GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)) { field.SetValue(target, field.GetValue(proxy)); } } } public class AddToSubtractInterceptor : IInterceptor { public void Intercept(IInvocation invocation) { // 先执行原方法 invocation.Proceed(); // 针对两数相加的场景,直接修改返回值为减法结果 if (invocation.Method.ReturnType == typeof(int) && invocation.Arguments.Length == 2) { var num1 = (int)invocation.Arguments[0]; var num2 = (int)invocation.Arguments[1]; invocation.ReturnValue = num1 - num2; } } }
说明:
- 无需修改
Service类代码,仅需继承Mutator即可生效 - 上述为简化实现,通用场景可配合
Mono.Cecil库直接修改IL指令,替换加法操作码为减法
方案二:编译时代码织入(Roslyn源代码生成器)
利用Roslyn编写源代码生成器,在编译阶段自动检测继承自Mutator的类,将其中的加法表达式替换为减法表达式。
实现步骤:
- 创建.NET Standard类库作为源代码生成器项目
- 编写生成器逻辑:
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; [Generator] public class AddToSubtractGenerator : ISourceGenerator { public void Initialize(GeneratorInitializationContext context) { context.RegisterForSyntaxNotifications(() => new MutatorClassReceiver()); } public void Execute(GeneratorExecutionContext context) { var receiver = (MutatorClassReceiver)context.SyntaxReceiver; foreach (var classNode in receiver.TargetClasses) { var semanticModel = context.Compilation.GetSemanticModel(classNode.SyntaxTree); var classSymbol = semanticModel.GetDeclaredSymbol(classNode); // 遍历类中所有方法,替换加法表达式 foreach (var method in classSymbol.GetMembers().OfType<IMethodSymbol>()) { var methodSyntax = method.DeclaringSyntaxReferences.First().GetSyntax() as MethodDeclarationSyntax; if (methodSyntax == null) continue; var modifiedMethod = methodSyntax.ReplaceNodes( methodSyntax.DescendantNodes().OfType<BinaryExpressionSyntax>(), (node, _) => node.Kind() == SyntaxKind.AddExpression ? SyntaxFactory.BinaryExpression(SyntaxKind.SubtractExpression, node.Left, node.Right) : node); // 生成修改后的代码文件 context.AddSource($"{classSymbol.Name}_{method.Name}.generated.cs", modifiedMethod.ToFullString()); } } } // 语法接收器:收集所有继承自Mutator的类 private class MutatorClassReceiver : ISyntaxReceiver { public List<ClassDeclarationSyntax> TargetClasses { get; } = new(); public void OnVisitSyntaxNode(SyntaxNode node) { if (node is ClassDeclarationSyntax classDec && classDec.BaseList?.Types.Any(t => t.Type.ToString() == "Mutator") == true) { TargetClasses.Add(classDec); } } } }
说明:
- 编译阶段自动完成代码替换,运行时无额外性能开销
- 业务类仅需继承
Mutator,无需其他修改
内容的提问来源于stack exchange,提问作者Mao Shengelia
相关产品推荐
相关产品推荐

