当前位置:网站首页>Metalama简介4.使用Fabric操作项目或命名空间
Metalama简介4.使用Fabric操作项目或命名空间
2022-04-23 13:01:00 【重典】
Metalama中的Fabric可以做什么
Fabric通过修改项目、命名空间、类型来达到一些效果,这引起修改包括:添加Aspect或添加代码分析
使用Fabric为指定的方法添加Aspect
前文中我们写过一个简单的Aspect:
public class LogAttribute : OverrideMethodAspect
{
public override dynamic? OverrideMethod()
{
Console.WriteLine(meta.Target.Method.ToDisplayString() + " 开始运行.");
var result = meta.Proceed();
Console.WriteLine(meta.Target.Method.ToDisplayString() + " 结束运行.");
return result;
}
}
当我们使用它时,我们要在对应的方法上添加这个Attribute:
[Log]
private static int Add(int a, int b) //... ...
那么当我们有一个Aspect要在项目中大量使用时,在每个方法上添加这个Aspect当然是一种方法,但是这种方法有2个缺点:
- 包含大量的重复代码
[Log] - 对于原代码的入侵性太强
此时我们就可以使用Fabric为所有符合要求的方法添加指定的Aspect:
internal class Fabric : ProjectFabric
{
// 这个是重写项目的Fabric中修改项目的方法
public override void AmendProject(IProjectAmender amender)
{
// 添加 LogAttribute 到符合规则的方法上
// 为名为 Add 且 private 的方法添加 LogAttribute
amender.WithTargetMembers(c =>
c.Types.SelectMany(t => t.Methods)
.Where(t =>
t.Name == "Add" &&
t.Accessibility == Metalama.Framework.Code.Accessibility.Private)
).AddAspect(t => new LogAttribute());
}
}
这样就可以在不入侵现有代码的情况下为指定的方法添加Aspect。
使用Fabric添加代码分析
上文中我们提到,我们可以通过Aspect为代码添加代码分析,当我们要将一个包含(且仅包含)代码分析的Aspect应用于一批代码时,当然我们可以按本文示例1中的方法,直接使用Fabric将包含代码分析的Aspect应用于指定代码。
但还有另外一种方法,我们可以直接在Fabric中定义应用于指定代码的代码分析。
下面示例,我们验证所有类中的私有字段必须符合 _camelCase,并且使用一个NamespaceFabric来实现:
namespace FabricCamelCaseDemo;
class Fabric : NamespaceFabric
{
private static readonly DiagnosticDefinition<string> _warning = new(
"DEMO04",
Severity.Warning,
"'{0}'必须使用驼峰命名法并以'_'开头");
// 这个是命名空间的Fabric中修改命名空间规则 的方法
public override void AmendNamespace(INamespaceAmender amender)
{
// 取所有非static 的private的字段,并添加代码分析
amender.WithTargetMembers(c =>
c.AllTypes.SelectMany(t=>t.Fields)
.Where(t => t.Accessibility == Accessibility.Private && !t.IsStatic
)
)
//preview 0.5.8之前为 RegisterFinalValidator
.Validate(this.FinalValidator);
}
private void FinalValidator(in DeclarationValidationContext context)
{
var fullname = context.Declaration.ToDisplayString();
var fieldName = fullname.Split('.').LastOrDefault();
if (fieldName!=null && (!fieldName.StartsWith("_") || !char.IsLower(fieldName[1])))
{
context.Diagnostics.Report(_warning.WithArguments(fieldName));
}
}
}
当然因为当前使用的是NamespaceFabric所以该规则只应用于当前命名空间如,我们如果在另外一个命名空间中定义一个违反规则的字段的话,并不会有警告。
namespace FabricCamelCase;
internal class OtherNamespace
{
int count = 0;
int _total = 0;
public int Add()
{
count++;
_total++;
return count + _total;
}
}
使用TypeFabric为类型动态添加方法
开始前伪造一个需求,假设我有一个类AddUtils专门处理加法操作,它里面应该有从2个到15个参数的Add方法15个(当然我知道,可以使用params等方法实现,所以这里是个伪需求)。
最终效果为
public class AddUtils
{
public int Add2(int x1, int x2)
{
var result = 0;
result += x1;
result += x2;
return 2;
}
public int Add3(int x1, int x2, int x3)
{
var result = 0;
result += x1;
result += x2;
result += x3;
return 3;
}
// 以此类推... 下面省去若干方法
}
那么我们可以用Metalama如此实现
using System.Reflection.Emit;
using Metalama.Framework.Aspects;
using Metalama.Framework.Fabrics;
public class AddUtils
{
private class Fabric : TypeFabric
{
// 实现的方法体
[Template]
public int MethodTemplate()
{
var num = (int) meta.Tags["nums"]!;
var result = 0;
foreach (var targetParameter in meta.Target.Parameters)
{
result += targetParameter.Value;
}
return num;
}
public override void AmendType(ITypeAmender amender)
{
for (var i = 2; i < 15; i++)
{
// 生成一个方法
var methodBuilder = amender.Advices.IntroduceMethod(
amender.Type,
nameof(this.MethodTemplate),
tags: new TagDictionary { ["nums"] = i });
// 方法名
methodBuilder.Name = "Add" + i;
// 添加参数
for (int parameterIndex = 1; parameterIndex <= i; parameterIndex++)
{
methodBuilder.AddParameter($"x{parameterIndex}", typeof(int));
}
}
}
}
}
引用
本章源代码:https://github.com/chsword/metalama-demo
Metalama官方文档: https://doc.metalama.net/
Metalama Nuget包: https://www.nuget.org/packages/Metalama.Framework/0.5.11-preview
版权声明
本文为[重典]所创,转载请带上原文链接,感谢
https://cloud.tencent.com/developer/article/1986099
边栏推荐
- JMeter operation redis
- 如何实现点击一下物体播放一次动画
- BaseRecyclerViewAdapterHelper 实现下拉刷新和上拉加载
- Translation of multi modal visual tracking: review and empirical comparison
- Teach you to quickly develop a werewolf killing wechat applet (with source code)
- MySQL supports IP access
- unity常见的问题(一)
- Start mqbroker CMD failure resolution
- Remote access to raspberry pie at home (Part 1)
- jmeter操作redis
猜你喜欢

Huawei cloud MVP email

风尚云网学习-h5的input:type属性的image属性

Free and open source charging pile Internet of things cloud platform

8 websites that should be known for product development to enhance work experience

SSM framework series - data source configuration day2-1

Process virtual address space partition

梳理网络IP代理的几大用途

Van uploader upload picture implementation process, using native input to upload pictures

在线计算过往日期天数,计算活了多少天

22. 括号生成
随机推荐
Van uploader upload picture implementation process, using native input to upload pictures
Record the problems encountered in using v-print
Use Proteus to simulate STM32 ultrasonic srf04 ranging! Code+Proteus
Use of Presto date function
If you were a golang interviewer, what questions would you ask?
Jupiter notebook installation
Record some NPM related problems (messy records)
Go language array operation
Ad20 supplementary note 3 - shortcut key + continuous update
mysql支持ip访问
Object.keys后key值数组乱序的问题
梳理網絡IP代理的幾大用途
SSM framework series - JUnit unit test optimization day2-3
Fashion cloud learning - input attribute summary
Importerror after tensorflow installation: DLL load failed: the specified module cannot be found, and the domestic installation is slow
22. Bracket generation
31. Next arrangement
leetcode:437. Path sum III [DFS selected or not selected?]
Recovering data with MySQL binlog
Record Alibaba cloud server mining program processing