Files
TouchSocket/handbook/docs/dynamicmethod.mdx
若汝棋茗 72e0a65742 feat(docs): 添加多个组件的导入和解析功能
在多个 `.mdx` 文件中添加对 `TouchSocketCoreDefinition`、`TouchSocketHttpDefinition`、`TouchSocketDmtpDefinition`、`TouchSocketModbusDefinition`、`TouchSocketProModbusDefinition`、`TouchSocketNamedPipeDefinition`、`TouchSocketWebApiDefinition`、`TouchSocketJsonRpcDefinition` 和 `TouchSocketXmlRpcDefinition` 的导入。增加解析和处理定义部分的 JavaScript 脚本,确保导入的有效性和一致性。新增功能包括精确匹配定义部分的正则表达式、解析定义内容的函数、生成定义组件的函数、递归查找 `.mdx` 文件的功能,以及验证导入的有效性
2025-07-09 22:22:17 +08:00

486 lines
18 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
id: dynamicmethod
title: 动态方法调用(DynamicMethod)
---
import CardLink from "@site/src/components/CardLink.js";
import { TouchSocketCoreDefinition } from "@site/src/components/Definition.js";
### 定义
<TouchSocketCoreDefinition />
## 一、核心概念
动态方法调用模块提供高效、灵活的方法反射调用方案支持多种底层实现方式显著提升反射调用性能。特别针对AOTAhead-of-Time编译环境优化同时保持传统反射场景的高性能表现。
## 二、核心特性
- **多引擎支持**
- IL代码生成DynamicBuilderType.IL
- 表达式树DynamicBuilderType.Expression
- 传统反射DynamicBuilderType.Reflect
- 源生成DynamicBuilderType.SourceGenerator
- **性能卓越**相比原生反射调用性能提升10倍性能
- **AOT友好**源生成模式实现零反射完美支持iOS/Android等AOT环境
- **智能异步支持**自动识别Task/ValueTask返回值类型
- **全参数支持**支持ref/out参数、泛型参数、参数默认值
- **灵活扩展**:支持自定义动态方法特性标记
## 三、快速开始
### 3.1 基本声明
```csharp showLineNumbers
public class MyClass
{
[DynamicMethod]
public void SimpleMethod()
{
Console.WriteLine("Method executed");
}
}
```
### 3.2 基础调用
```csharp showLineNumbers
// 创建方法包装器
var method = new Method(typeof(MyClass), nameof(MyClass.SimpleMethod));
// 实例化对象
var instance = new MyClass();
// 执行方法调用
method.Invoke(instance);
```
## 四、核心功能详解
### 4.1 构建器类型选择
```csharp showLineNumbers
// 使用IL生成
var ilMethod = new Method(
typeof(MyClass),
nameof(MyClass.SimpleMethod),
DynamicBuilderType.IL
);
// 使用表达式树
var exprMethod = new Method(
typeof(MyClass),
nameof(MyClass.SimpleMethod),
DynamicBuilderType.Expression
);
// 使用源生成性能最强AOT环境推荐
var sourceGenMethod = new Method(
typeof(MyClass),
nameof(MyClass.SimpleMethod),
DynamicBuilderType.SourceGenerator
);
```
:::tip 构建器选择建议
- **任何时候**使用SourceGenerator无论性能还是AOT环境都是首选。
:::
### 4.2 异步方法支持
```csharp showLineNumbers
public class MyClass
{
[DynamicMethod]
public async Task<int> GetDataAsync()
{
await Task.Delay(100);
return 42;
}
}
// 异步调用
var method = new Method(typeof(MyClass), nameof(MyClass.GetDataAsync));
var result = await method.InvokeAsync(instance);
Console.WriteLine($"Result: {result}"); // 输出 42
```
### 4.3 复杂参数处理
```csharp showLineNumbers
public class MyClass
{
[DynamicMethod]
public void ProcessData(
string input,
ref int counter,
out string result)
{
counter++;
result = $"{input}_{counter}";
}
}
// 调用示例
var parameters = new object[] { "data", 0, null };
method.Invoke(instance, parameters);
Console.WriteLine($"Result: {parameters[2]}"); // 输出 "data_1"
```
## 五、性能优化
### 5.1 性能对比测试
:::tip 10000次调用性能分析
**核心结论**
1. **同步方法Add性能**
- **直接调用** 最快(~2.1µs无内存分配。
- **源生成器SourceGeneratorRun** 在 .NET 8+ 接近直接调用性能(~3.1µs较 IL/表达式树快 6-7 倍,较反射快 28-30 倍。
- **反射MethodInfo** 性能最差(.NET 6: 400µs → .NET 8: 88µs.NET 8+ 反射性能显著优化。
2. **异步方法AddAsync性能**
- **直接调用** 仍最优(.NET 8: 38µs.NET 9: 39µs
- **源生成器** 表现接近 IL/表达式树(.NET 8: 91µs vs 103µs较反射快 2-3 倍(.NET 8: 91µs vs 184µs
- **.NET Framework 4.8.1** 异步性能最差(反射达 1,305µs内存分配显著高于其他版本。
3. **内存分配**
- 同步方法:源生成器与 IL/表达式树分配 80B反射额外多 1B.NET 6
- 异步方法:所有动态方法分配 ~720KB.NET Core或 ~802KBFramework反射在 Framework 分配超 1MB。
**附:关键数据对比(.NET 8**
| 方法 | 同步耗时 | 异步耗时 | 内存分配 |
|----------------------|---------|---------|----------|
| DirectRun | 2.1µs | 38µs | 56B |
| SourceGeneratorRun | 3.1µs | 91µs | 80B |
| MethodInfoRun | 88µs | 184µs | 80B |
:::
```csharp {7,12,18,23,29,34,40,45} showLineNumbers
| Method | Job | Runtime | Mean | Error | StdDev | Gen0 | Gen1 | Allocated |
|----------------------------- |--------------------- |--------------------- |-------------:|----------:|----------:|---------:|-------:|----------:|
| DirectRun_Add | .NET 6.0 | .NET 6.0 | 2.132 us | 0.0031 us | 0.0027 us | - | - | 56 B |
| MethodILRun_Add | .NET 6.0 | .NET 6.0 | 23.887 us | 0.0795 us | 0.0744 us | - | - | 80 B |
| MethodExpressionRun_Add | .NET 6.0 | .NET 6.0 | 20.108 us | 0.1542 us | 0.1443 us | - | - | 80 B |
| MethodInfoRun_Add | .NET 6.0 | .NET 6.0 | 399.999 us | 0.3781 us | 0.3537 us | - | - | 81 B |
| SourceGeneratorRun_Add | .NET 6.0 | .NET 6.0 | 17.648 us | 0.0945 us | 0.0884 us | - | - | 80 B |
| DirectRun_AddAsync | .NET 6.0 | .NET 6.0 | 46.567 us | 0.4623 us | 0.4098 us | 45.8984 | - | 720080 B |
| MethodILRun_AddAsync | .NET 6.0 | .NET 6.0 | 141.010 us | 0.8145 us | 0.7619 us | 45.8984 | - | 720080 B |
| MethodExpressionRun_AddAsync | .NET 6.0 | .NET 6.0 | 142.758 us | 0.8197 us | 0.7266 us | 45.8984 | - | 720080 B |
| MethodInfoRun_AddAsync | .NET 6.0 | .NET 6.0 | 563.645 us | 1.8681 us | 1.6560 us | 45.8984 | - | 720081 B |
| SourceGeneratorRun_AddAsync | .NET 6.0 | .NET 6.0 | 141.399 us | 0.8781 us | 0.8214 us | 45.8984 | - | 720080 B |
| StaticMethodRun | .NET 6.0 | .NET 6.0 | 2.130 us | 0.0018 us | 0.0017 us | - | - | 56 B |
| DirectRun_Add | .NET 8.0 | .NET 8.0 | 2.140 us | 0.0116 us | 0.0109 us | - | - | 56 B |
| MethodILRun_Add | .NET 8.0 | .NET 8.0 | 19.332 us | 0.0491 us | 0.0459 us | - | - | 80 B |
| MethodExpressionRun_Add | .NET 8.0 | .NET 8.0 | 12.889 us | 0.1189 us | 0.1054 us | - | - | 80 B |
| MethodInfoRun_Add | .NET 8.0 | .NET 8.0 | 88.879 us | 0.1784 us | 0.1581 us | - | - | 80 B |
| SourceGeneratorRun_Add | .NET 8.0 | .NET 8.0 | 3.160 us | 0.0073 us | 0.0068 us | 0.0038 | - | 80 B |
| DirectRun_AddAsync | .NET 8.0 | .NET 8.0 | 38.401 us | 0.1199 us | 0.1063 us | 45.8984 | - | 720080 B |
| MethodILRun_AddAsync | .NET 8.0 | .NET 8.0 | 103.627 us | 1.2387 us | 1.1587 us | 45.8984 | - | 720080 B |
| MethodExpressionRun_AddAsync | .NET 8.0 | .NET 8.0 | 101.368 us | 0.7190 us | 0.6725 us | 45.8984 | - | 720080 B |
| MethodInfoRun_AddAsync | .NET 8.0 | .NET 8.0 | 183.882 us | 0.7238 us | 0.6044 us | 45.8984 | - | 720080 B |
| SourceGeneratorRun_AddAsync | .NET 8.0 | .NET 8.0 | 91.024 us | 0.6482 us | 0.6063 us | 45.8984 | - | 720080 B |
| StaticMethodRun | .NET 8.0 | .NET 8.0 | 2.150 us | 0.0073 us | 0.0068 us | - | - | 56 B |
| DirectRun_Add | .NET 9.0 | .NET 9.0 | 2.119 us | 0.0024 us | 0.0022 us | - | - | 56 B |
| MethodILRun_Add | .NET 9.0 | .NET 9.0 | 19.348 us | 0.0133 us | 0.0124 us | - | - | 80 B |
| MethodExpressionRun_Add | .NET 9.0 | .NET 9.0 | 11.753 us | 0.0625 us | 0.0585 us | - | - | 80 B |
| MethodInfoRun_Add | .NET 9.0 | .NET 9.0 | 91.756 us | 0.2344 us | 0.2193 us | - | - | 80 B |
| SourceGeneratorRun_Add | .NET 9.0 | .NET 9.0 | 3.145 us | 0.0056 us | 0.0046 us | 0.0038 | - | 80 B |
| DirectRun_AddAsync | .NET 9.0 | .NET 9.0 | 39.219 us | 0.1669 us | 0.1561 us | 45.8984 | - | 720080 B |
| MethodILRun_AddAsync | .NET 9.0 | .NET 9.0 | 107.920 us | 0.4728 us | 0.4191 us | 45.8984 | - | 720080 B |
| MethodExpressionRun_AddAsync | .NET 9.0 | .NET 9.0 | 106.539 us | 0.3894 us | 0.3642 us | 45.8984 | - | 720080 B |
| MethodInfoRun_AddAsync | .NET 9.0 | .NET 9.0 | 189.294 us | 0.7231 us | 0.6764 us | 45.8984 | - | 720080 B |
| SourceGeneratorRun_AddAsync | .NET 9.0 | .NET 9.0 | 99.195 us | 0.3677 us | 0.3440 us | 45.8984 | - | 720080 B |
| StaticMethodRun | .NET 9.0 | .NET 9.0 | 2.125 us | 0.0036 us | 0.0034 us | - | - | 56 B |
| DirectRun_Add | .NET Framework 4.8.1 | .NET Framework 4.8.1 | 2.134 us | 0.0047 us | 0.0042 us | 0.0076 | - | 56 B |
| MethodILRun_Add | .NET Framework 4.8.1 | .NET Framework 4.8.1 | 30.162 us | 0.0629 us | 0.0588 us | - | - | 80 B |
| MethodExpressionRun_Add | .NET Framework 4.8.1 | .NET Framework 4.8.1 | 56.063 us | 0.0559 us | 0.0467 us | - | - | 80 B |
| MethodInfoRun_Add | .NET Framework 4.8.1 | .NET Framework 4.8.1 | 770.931 us | 5.9446 us | 5.5606 us | 50.7813 | - | 321027 B |
| SourceGeneratorRun_Add | .NET Framework 4.8.1 | .NET Framework 4.8.1 | 17.521 us | 0.0350 us | 0.0310 us | - | - | 80 B |
| DirectRun_AddAsync | .NET Framework 4.8.1 | .NET Framework 4.8.1 | 41.866 us | 0.1300 us | 0.1216 us | 127.5024 | 0.0610 | 802442 B |
| MethodILRun_AddAsync | .NET Framework 4.8.1 | .NET Framework 4.8.1 | 523.507 us | 2.1568 us | 1.9120 us | 126.9531 | - | 802445 B |
| MethodExpressionRun_AddAsync | .NET Framework 4.8.1 | .NET Framework 4.8.1 | 554.333 us | 2.3657 us | 2.2129 us | 126.9531 | - | 802445 B |
| MethodInfoRun_AddAsync | .NET Framework 4.8.1 | .NET Framework 4.8.1 | 1,304.826 us | 1.4392 us | 1.2758 us | 177.7344 | - | 1123389 B |
| SourceGeneratorRun_AddAsync | .NET Framework 4.8.1 | .NET Framework 4.8.1 | 508.533 us | 0.8991 us | 0.8410 us | 126.9531 | - | 802445 B |
| StaticMethodRun | .NET Framework 4.8.1 | .NET Framework 4.8.1 | 3.267 us | 0.0070 us | 0.0062 us | 0.0114 | - | 80 B |
```
<details>
<summary>基准测试代码</summary>
<div>
```csharp showLineNumbers
[SimpleJob(RuntimeMoniker.Net481)]
[SimpleJob(RuntimeMoniker.Net60)]
[SimpleJob(RuntimeMoniker.Net80)]
[SimpleJob(RuntimeMoniker.Net90)]
[MemoryDiagnoser]
public class BenchmarkInvokeMethodClass
{
public BenchmarkInvokeMethodClass()
{
var methodInfo_Add = typeof(MyMethodClass1).GetMethod(nameof(MyMethodClass1.Add));
var methodInfo_AddAsync = typeof(MyMethodClass1).GetMethod(nameof(MyMethodClass1.AddAsync));
this.m_method_Add_IL = new Method(methodInfo_Add, DynamicBuilderType.IL);
this.m_method_Add_Expression = new Method(methodInfo_Add, DynamicBuilderType.Expression);
this.m_method_Add_SourceGenerator = new Method(methodInfo_Add, DynamicBuilderType.SourceGenerator);
this.m_method_Add_Reflect = new Method(methodInfo_Add, DynamicBuilderType.Reflect);
this.m_method_AddAsync_IL = new Method(methodInfo_AddAsync, DynamicBuilderType.IL);
this.m_method_AddAsync_Expression = new Method(methodInfo_AddAsync, DynamicBuilderType.Expression);
this.m_method_AddAsync_SourceGenerator = new Method(methodInfo_AddAsync, DynamicBuilderType.SourceGenerator);
this.m_method_AddAsync_Reflect = new Method(methodInfo_AddAsync, DynamicBuilderType.Reflect);
var AddStatic = typeof(MyMethodClass1).GetProperty("AddStaticAction");
}
private readonly Method m_method_Add_IL;
private readonly Method m_method_Add_Expression;
private readonly Method m_method_Add_SourceGenerator;
private readonly Method m_method_Add_Reflect;
private readonly Method m_method_AddAsync_IL;
private readonly Method m_method_AddAsync_Expression;
private readonly Method m_method_AddAsync_SourceGenerator;
private readonly Method m_method_AddAsync_Reflect;
public int Count=10000;
[Benchmark]
public void DirectRun_Add()
{
var myClass1 = new MyMethodClass1();
var a = new object();
var objects = new object[] { a };
for (var i = 0; i < this.Count; i++)
{
myClass1.Add(a);
}
}
[Benchmark]
public void MethodILRun_Add()
{
var myClass2 = new MyMethodClass1();
var a = new object();
var objects = new object[] { a };
for (var i = 0; i < this.Count; i++)
{
this.m_method_Add_IL.Invoke(myClass2, objects);
}
}
[Benchmark]
public void MethodExpressionRun_Add()
{
var myClass2 = new MyMethodClass1();
var a = new object();
var objects = new object[] { a };
for (var i = 0; i < this.Count; i++)
{
this.m_method_Add_Expression.Invoke(myClass2, objects);
}
}
[Benchmark]
public void MethodInfoRun_Add()
{
var myClass2 = new MyMethodClass1();
var a = new object();
var objects = new object[] { a };
for (var i = 0; i < this.Count; i++)
{
this.m_method_Add_Reflect.Invoke(myClass2, objects);
}
}
[Benchmark]
public void SourceGeneratorRun_Add()
{
var myClass2 = new MyMethodClass1();
var a = new object();
var objects = new object[] { a };
for (var i = 0; i < this.Count; i++)
{
this.m_method_Add_SourceGenerator.Invoke(myClass2, objects);
}
}
[Benchmark]
public async Task DirectRun_AddAsync()
{
var myClass1 = new MyMethodClass1();
var a = new object();
var objects = new object[] { a };
for (var i = 0; i < this.Count; i++)
{
await myClass1.AddAsync(a);
}
}
[Benchmark]
public async Task MethodILRun_AddAsync()
{
var myClass2 = new MyMethodClass1();
var a = new object();
var objects = new object[] { a };
for (var i = 0; i < this.Count; i++)
{
await this.m_method_Add_IL.InvokeAsync(myClass2, objects);
}
}
[Benchmark]
public async Task MethodExpressionRun_AddAsync()
{
var myClass2 = new MyMethodClass1();
var a = new object();
var objects = new object[] { a };
for (var i = 0; i < this.Count; i++)
{
await this.m_method_Add_Expression.InvokeAsync(myClass2, objects);
}
}
[Benchmark]
public async Task MethodInfoRun_AddAsync()
{
var myClass2 = new MyMethodClass1();
var a = new object();
var objects = new object[] { a };
for (var i = 0; i < this.Count; i++)
{
await this.m_method_Add_Reflect.InvokeAsync(myClass2, objects);
}
}
[Benchmark]
public async Task SourceGeneratorRun_AddAsync()
{
var myClass2 = new MyMethodClass1();
var a = new object();
var objects = new object[] { a };
for (var i = 0; i < this.Count; i++)
{
await this.m_method_Add_SourceGenerator.InvokeAsync(myClass2, objects);
}
}
[Benchmark]
public void StaticMethodRun()
{
var myClass1 = new MyMethodClass1();
var a = new object();
var objects = new object[] { a };
for (var i = 0; i < this.Count; i++)
{
MyMethodClass1.AddStatic(myClass1, objects);
}
}
}
public class MyMethodClass1
{
public static object AddStatic(object myClass, object[] ps)
{
var a = ps[0];
var result = ((MyMethodClass1)myClass).Add(a);
return result;
}
//这个是被调用函数。
[DynamicMethod]
public object Add(object obj)
{
return obj;
}
[DynamicMethod]
public Task<object> AddAsync(object obj)
{
return Task.FromResult(obj);
}
}
```
</div>
</details>
### 5.2 缓存策略
```csharp showLineNumbers
// 推荐在应用初始化时预加载方法
public static class MethodCache
{
public static readonly Method ProcessMethod = new Method(
typeof(MyClass),
nameof(MyClass.ProcessData),
DynamicBuilderType.IL
);
}
// 后续重复使用缓存实例
MethodCache.ProcessMethod.Invoke(instance);
```
## 六、高级用法
### 6.1 自定义特性标记
```csharp showLineNumbers
// 定义自定义特性
[AttributeUsage(AttributeTargets.Method)]
public class MyDynamicAttribute : DynamicMethodAttribute {}
// 标记方法
public class CustomService
{
[MyDynamic]
public void CustomOperation() { }
}
// 获取自定义标记方法
var methods = typeof(CustomService)
.GetMethods()
.Where(m => m.IsDefined(typeof(MyDynamicAttribute)));
```
## 七、示例项目
<CardLink link="https://gitee.com/RRQM_Home/TouchSocket/tree/master/examples/Core/AotDynamicMethodConsoleApp"/>