Csharp Dotnetcore Natasha
/install csharp-dotnetcore-natasha
\r \r
Natasha C# Dynamic Compilation Skill\r
\r
Purpose\r
\r This skill enables developers to dynamically generate and compile C# code at runtime using the Natasha library. It supports creating dynamic classes, generating high-performance delegates, accessing private members of existing types, managing isolated compilation contexts, and precisely controlling metadata loading strategies.\r \r
When to Use This Skill\r
\r Use this skill when:\r \r
- Dynamically creating classes with custom properties and methods at runtime\r
- Generating high-performance delegates for computational code without reflection overhead\r
- Accessing private fields or methods of existing types from dynamically compiled code\r
- Building expression trees or code generation utilities that require runtime C# compilation\r
- Creating extensible plugin systems where behavior is determined at runtime\r
- Optimizing performance-critical code paths through dynamic method generation\r
- Needing fine-grained control over metadata and using-code scope (lean metadata mode)\r \r
How to Use This Skill\r
\r
Prerequisites\r
\r Install the required NuGet packages in your project:\r \r
# Core compiler package (基础编译单元)\r
dotnet add package DotNetCore.Natasha.CSharp.Compiler\r
\r
# Domain implementation package (域实现包)\r
dotnet add package DotNetCore.Natasha.CSharp.Compiler.Domain\r
```\r
\r
**Note:** `DotNetCore.Natasha.CSharp.Compiler.Domain` inherits from `DotNetCore.Natasha.Domain` and implements the compilation binding interface required by Natasha compiler. All packages are prefixed with `DotNetCore.`\r
\r
**Framework Support:** .NET Core 3.1+, .NET 5.0+, .NET 6.0+, .NET 7.0+, .NET 8.0+\r
\r
---\r
\r
## Three Compilation Modes\r
\r
### Mode 1: Smart Mode (智能模式) — Recommended for Most Cases\r
\r
Smart mode automatically merges metadata and using-code from the default domain + current domain, with semantic checking enabled.\r
\r
**Key decision: Memory Assembly vs Reference Assembly**\r
\r
| Dimension | Memory Assembly | Reference Assembly |\r
|-----------|----------------|--------------------|\r
| Metadata coverage | Runtime types only | Complete metadata (including non-loaded assemblies) |\r
| Memory usage | Lower | Higher |\r
| Startup speed | Faster | Slower |\r
| Recommended for | Most scenarios | Full metadata needed, memory/size not a concern |\r
\r
**Memory assembly initialization (内存程序集预热):**\r
```csharp\r
NatashaManagement\r
.GetInitializer()\r
.WithMemoryUsing() // Extract using-code from in-memory assemblies\r
.WithMemoryReference() // Extract metadata from in-memory assemblies\r
.Preheating\x3CNatashaDomainCreator>();\r
```\r
\r
**Reference assembly initialization (引用程序集预热):**\r
```csharp\r
NatashaManagement\r
.GetInitializer()\r
.WithRefUsing() // Extract using-code from reference assembly files\r
.WithRefReference() // Extract metadata from reference assembly files (most complete)\r
.Preheating\x3CNatashaDomainCreator>();\r
```\r
\r
> **Rule of thumb:** If the user does not care about program size or memory consumption, use `WithRefUsing().WithRefReference()` — reference assemblies provide the most complete metadata coverage.\r
\r
**Using file cache (文件缓存优化):**\r
\r
When the project is stable (no more new dependencies being added), enable `WithFileUsingCache()` to write using-code into a `Natasha.Namespace.cache` file. On subsequent runs, Natasha reads from the cache instead of scanning assemblies, significantly speeding up startup:\r
\r
```csharp\r
NatashaManagement\r
.GetInitializer()\r
.WithMemoryUsing()\r
.WithMemoryReference()\r
.WithFileUsingCache() // Cache using-code to disk (use when dependencies are stable)\r
.Preheating\x3CNatashaDomainCreator>();\r
```\r
\r
**Usage in smart mode:**\r
```csharp\r
AssemblyCSharpBuilder builder = new();\r
builder\r
.UseRandomLoadContext()\r
.UseSmartMode() // Merges current + default domain refs, enables semantic check\r
.Add("public class A { public int Value { get; set; } }");\r
\r
var assembly = builder.GetAssembly();\r
```\r
\r
### Mode 2: Simple Mode (精简模式 / 自管理元数据模式)\r
\r
Use simple mode when you need to precisely control which metadata participates in compilation. No global preheating metadata is used — you add only what you need via `ConfigLoadContext`.\r
\r
```csharp\r
// No global Preheating() needed for simple mode\r
NatashaManagement.RegistDomainCreator\x3CNatashaDomainCreator>();\r
\r
AssemblyCSharpBuilder builder = new();\r
builder\r
.UseRandomLoadContext()\r
.UseSimpleMode() // No combined references, no semantic check\r
.ConfigLoadContext(ldc => ldc\r
.AddReferenceAndUsingCode(typeof(Math).Assembly) // Adds Math + all its deps\r
.AddReferenceAndUsingCode(typeof(MathF)) // Adds MathF's assembly\r
.AddReferenceAndUsingCode(typeof(object))) // Adds core runtime\r
.Add("public static class A { public static double Calc(double v) { return Math.Floor(v/0.3); } }");\r
\r
var assembly = builder.GetAssembly();\r
```\r
\r
**Key points for simple mode:**\r
- `AddReferenceAndUsingCode(typeof(T))` — loads T's assembly AND its dependency assemblies, plus extracts all using-code from them\r
- `AddReferenceAndUsingCode(typeof(T).Assembly)` — same but takes an Assembly object\r
- The `using` directives are automatically collected from the added assemblies in simple mode, so you don't need to write them explicitly in the script (unless using `WithoutCombineUsingCode`)\r
- Use `AppendExceptUsings("System.IO", "MyNamespace")` to explicitly exclude certain using namespaces from being injected into the syntax tree\r
\r
### Mode 3: Custom Compilation Mode (自定义编译模式)\r
\r
Use when you provide your own complete metadata set (e.g., from `Basic.Reference.Assemblies` NuGet package) and handle using-code yourself.\r
\r
```csharp\r
// You prepare the metadata collection yourself, e.g. from Basic.Reference.Assemblies\r
IEnumerable\x3CMetadataReference> myRefs = Basic.Reference.Assemblies.Net80.References.All;\r
\r
AssemblyCSharpBuilder builder = new();\r
builder\r
.UseRandomDomain()\r
.WithSpecifiedReferences(myRefs) // Use ONLY these references (no domain refs)\r
.WithoutCombineUsingCode() // Do NOT auto-inject using-code\r
.WithReleaseCompile()\r
.Add("using System; using static System.Math; public static class A { public static int Test(int a, int b) { return a + b; } }");\r
// Note: when WithoutCombineUsingCode() is used, include using directives manually in your script\r
\r
var assembly = builder.GetAssembly();\r
```\r
\r
**`WithSpecifiedReferences`** makes the builder ignore both the default domain and current domain metadata, using only the explicitly provided references.\r
\r
---\r
\r
## Core Workflow\r
\r
1. **Initialize Natasha** (once per application startup)\r
- Choose smart or simple mode based on your needs\r
- Reference: See `references/initialization-patterns.md` for all supported initialization methods\r
\r
2. **Create AssemblyCSharpBuilder**\r
- Instantiate `new AssemblyCSharpBuilder()`\r
- Configure load context: `UseRandomLoadContext()` for isolation, `UseNewLoadContext("name")` for persistence\r
- Select compilation mode: `UseSmartMode()` / `UseSimpleMode()` / custom\r
- Set compilation level: `WithReleaseCompile()` or `WithDebugCompile()`\r
\r
3. **Add and Compile Code**\r
- Use `.Add(csharpCode)` to add code strings\r
- Call `.GetAssembly()` to compile and retrieve the assembly\r
- Or call `.CompileWithoutAssembly()` to compile without injecting into the domain\r
\r
4. **Extract and Use Generated Types**\r
- Use `GetTypeFromShortName("ClassName")` to retrieve compiled types\r
- Use `GetDelegateFromShortName\x3CT>("ClassName", "MethodName")` for delegates\r
\r
---\r
\r
## Three Core Usage Patterns\r
\r
### Pattern 1: Dynamic Class Generation\r
\r
```csharp\r
// Initialize (once at application startup)\r
NatashaManagement\r
.GetInitializer()\r
.WithMemoryUsing()\r
.WithMemoryReference()\r
.Preheating\x3CNatashaDomainCreator>();\r
\r
AssemblyCSharpBuilder builder = new();\r
builder\r
.UseRandomLoadContext()\r
.UseSmartMode();\r
\r
builder.Add(@"\r
public class DynamicPerson {\r
public string Name { get; set; }\r
public int Age { get; set; }\r
public string Greet() => $""Hello, I'm {Name}, age {Age}"";\r
}\r
");\r
\r
var assembly = builder.GetAssembly();\r
var personType = assembly.GetTypeFromShortName("DynamicPerson");\r
var instance = Activator.CreateInstance(personType);\r
personType.GetProperty("Name")!.SetValue(instance, "Alice");\r
var greeting = personType.GetMethod("Greet")!.Invoke(instance, null);\r
```\r
\r
### Pattern 2: Dynamic Delegate Generation\r
\r
```csharp\r
AssemblyCSharpBuilder builder = new();\r
builder\r
.UseRandomLoadContext()\r
.UseSmartMode()\r
.Add(@"\r
public class MathHelper {\r
public static int Add(int a, int b) => a + b;\r
}\r
");\r
\r
var assembly = builder.GetAssembly();\r
var addFunc = assembly.GetDelegateFromShortName\x3CFunc\x3Cint, int, int>>("MathHelper", "Add");\r
int result = addFunc(3, 5); // result: 8\r
```\r
\r
**Important:** The delegate type parameter `T` must exactly match the method signature.\r
\r
### Pattern 3: Accessing Private Members (V9 API)\r
\r
V9 introduces a cleaner API for private member access. Two key steps:\r
1. Call `builder.WithPrivateAccess()` to enable private compilation on the builder\r
2. Call `script.ToAccessPrivateTree(...)` to rewrite the syntax tree with access attributes\r
\r
```csharp\r
// Add IgnoresAccessChecksToAttribute.cs to your project (see references/troubleshooting.md)\r
\r
AssemblyCSharpBuilder builder = new();\r
builder\r
.UseRandomLoadContext()\r
.UseSmartMode()\r
.WithPrivateAccess(); // V9: enable private member access on the builder\r
\r
string script = @"\r
public class Accessor {\r
public static int GetSecret(UserModel model) {\r
return model._secret; // private field\r
}\r
}\r
";\r
\r
// Pass the target type (or namespace string, or instance) to ToAccessPrivateTree\r
builder.Add(script.ToAccessPrivateTree(typeof(UserModel)));\r
// OR: builder.Add(script.ToAccessPrivateTree("MyNamespace.Assembly", "OtherNamespace"));\r
// OR: builder.Add(script.ToAccessPrivateTree(instance1, instance2));\r
\r
var assembly = builder.GetAssembly();\r
var getSecret = assembly.GetDelegateFromShortName\x3CFunc\x3CUserModel, int>>("Accessor", "GetSecret");\r
```\r
\r
---\r
\r
## Load Context Management\r
\r
Different scenarios require different load context management strategies:\r
\r
- **Random context** (`UseRandomLoadContext()`): Each compilation creates a new isolated load context. Use for most cases where isolation is desired.\r
- **Named context** (`UseNewLoadContext("name")`): Create a persistent named context for reuse across multiple compilations.\r
- **Existing context** (`UseExistLoadContext(context)` or `UseExistLoadContext(domain)`): Compile in an existing context/domain, enabling cross-assembly type references.\r
- **Default context** (`UseDefaultLoadContext()`): Use the default shared context (least isolation).\r
\r
Reference: See `references/context-management.md` for detailed load context lifecycle patterns.\r
\r
---\r
\r
## Advanced & V9 Features\r
\r
### Reuse Optimization for Repeated Compilations\r
\r
When reusing a builder for multiple compilations, V9 provides reuse APIs to skip re-creating expensive objects:\r
\r
```csharp\r
builder\r
.WithPreCompilationOptions() // Reuse previous CSharpCompilationOptions (debug/release flags)\r
.WithPreCompilationReferences() // Reuse previous metadata reference set\r
.WithRandomAssenblyName() // Generate new GUID assembly name for each run\r
.Add(newCode)\r
.GetAssembly();\r
```\r
\r
> **Note:** Use `WithoutPreCompilationOptions()` (default) if you need to switch debug/release or unsafe/nullable between compilations.\r
\r
### Compile Without Injecting Assembly\r
\r
Use `CompileWithoutAssembly()` when you only need the compilation result (e.g., validation, syntax check) without loading the assembly into the domain:\r
\r
```csharp\r
builder.Add("public class A {}").CompileWithoutAssembly();\r
// Assembly is compiled but NOT injected into the load context domain\r
```\r
\r
### External Exception Retrieval\r
\r
V9 adds `GetException()` to retrieve compilation errors outside the compilation lifecycle:\r
\r
```csharp\r
var assembly = builder.GetAssembly(); // May suppress exceptions internally\r
var ex = builder.GetException(); // Retrieve if something went wrong\r
if (ex != null) { /* handle */ }\r
```\r
\r
### Excluding Specific Using Namespaces\r
\r
Prevent certain namespaces from being auto-injected into the syntax tree:\r
\r
```csharp\r
builder.AppendExceptUsings("System.IO", "System.Net", "MyConflictingNamespace");\r
```\r
\r
### Forced Output Cleanup on Repeated Compilation\r
\r
```csharp\r
builder.WithForceCleanOutput(); // Delete previous output file before recompiling\r
// Default: WithoutForceCleanOutput() — renames old file to repeate.{guid}.oldname\r
```\r
\r
### Debug Compilation Levels\r
\r
```csharp\r
// Standard debug (sufficient for most debugging needs)\r
builder.WithDebugCompile(opt => opt.ForCore());\r
\r
// Enhanced debug — more granular output including implicit conversions\r
builder.WithDebugPlusCompile(opt => opt.ForCore());\r
\r
// Release with debug info embedded (production tracing)\r
builder.WithReleasePlusCompile();\r
```\r
\r
> **Note:** Before using dynamic debugging, disable [Address-level debugging] in Tools → Options → Debugging.\r
\r
### Compiler Options\r
\r
Configure compiler behavior through `ConfigCompilerOption()`:\r
\r
```csharp\r
builder.ConfigCompilerOption(opt => opt\r
.AppendCompilerFlag(CompilerBinderFlags.IgnoreAccessibility) // Bypass access checks\r
.WithAllMetadata() // Access all metadata levels\r
.AppendNullableFlag(NullableContextOptions.Enable) // Enable nullable annotations\r
);\r
```\r
\r
Reference: See `references/compiler-options.md` for complete compiler configuration options.\r
\r
---\r
\r
## Important Notes\r
\r
### Core Concepts\r
\r
- **AssemblyCSharpBuilder** is the main API for dynamic compilation in Natasha\r
- **NatashaManagement** handles global initialization and compiler setup\r
- **Load Context** is what AssemblyCSharpBuilder uses internally via `UseRandomLoadContext()`, `UseNewLoadContext()`, etc.\r
- **Domain** (from `DotNetCore.Natasha.Domain`) is used separately for plugin management via `new NatashaDomain(key)` or `DomainManagement`\r
- **Do NOT confuse:** `UseNewLoadContext()` (AssemblyCSharpBuilder method) ≠ `new NatashaDomain(key)` (plugin system)\r
\r
### Modern API (Recommended)\r
\r
- **Always use:** `AssemblyCSharpBuilder` with `UseRandomLoadContext()` / `UseNewLoadContext()` / `UseSmartMode()`\r
- **Initialize once:** `NatashaManagement.GetInitializer().WithMemoryUsing().WithMemoryReference().Preheating\x3CNatashaDomainCreator>()`\r
- **Deprecated:** Old methods like `UseRandomDomain()`, `UseNewDomain()`, `UseDefaultDomain()` are marked `[Obsolete]` — use `UseRandomLoadContext()`, `UseDefaultLoadContext()` instead\r
\r
### Best Practices\r
\r
1. **Initialize once at application startup:** Do not reinitialize on every compilation\r
2. **Cache delegates:** Store compiled delegates for frequently used functions to avoid recompilation\r
3. **Choose the right mode:**\r
- Smart mode + memory refs → fast startup, adequate metadata\r
- Smart mode + ref assembly refs → slowest startup, most complete metadata\r
- Simple mode → precise control, minimal footprint\r
- Custom mode → you own everything, maximum control\r
4. **Use `WithFileUsingCache` when stable:** Only enable once the project's dependencies won't change\r
5. **Isolate contexts:** Use `UseRandomLoadContext()` to avoid load context pollution\r
6. **Handle errors:** Use `GetException()` after compilation to catch errors gracefully\r
\r
### Performance Considerations\r
\r
- Compiled delegates have zero reflection overhead after compilation\r
- First compilation has overhead for initializing the compilation service\r
- `WithPreCompilationOptions()` + `WithPreCompilationReferences()` significantly reduce repeated compilation overhead\r
- `WithFileUsingCache()` speeds up application restarts when dependencies are stable\r
- Subsequent compilations in the same named context are faster than random context compilations\r
\r
## Reference Files\r
\r
This skill includes the following reference materials:\r
\r
- `references/initialization-patterns.md` - Complete initialization method variations\r
- `references/context-management.md` - Load context lifecycle and management patterns\r
- `references/compiler-options.md` - Compiler configuration options and flags\r
- `references/migration-guide.md` - Migration from deprecated Template API\r
- `references/common-patterns.md` - Real-world usage patterns and recipes\r
- `references/troubleshooting.md` - Common errors and solutions\r
- `COMPILATION_ERROR_HANDLING.md` - 完整错误处理指南(推荐)\r
- `PRIVATE_MEMBER_ACCESS.md` - 私有成员访问最佳实践\r
- `REPEAT_COMPILE_OPTIMIZATION.md` - 重复编译优化分析\r
\r
Reference these files when encountering specific scenarios or needing detailed configuration guidance.\r
\r
## Additional Resources\r
\r
- **Natasha GitHub:** https://github.com/dotnetcore/Natasha\r
- **Official Documentation:** https://natasha.dotnetcore.xyz/zh-Hans/docs\r
- **NuGet Package (Compiler):** https://www.nuget.org/packages/DotNetCore.Natasha.CSharp.Compiler\r
- **NuGet Package (Domain):** https://www.nuget.org/packages/DotNetCore.Natasha.CSharp.Compiler.Domain\r
- **Source Code:** G:\Project\OpenSource\Natasha (all packages prefixed with `DotNetCore.`)\r
\r
---\r
\r
**Version:** 3.3\r
**Last Updated:** 2026-03-30\r
**Author Note:** V3.3: 深入源码学习,揭秘 GetAvailableCompilation() 核心流程、UsingAnalysistor 智能纠错原理、MethodCreator 内部实现、泛型 MethodInfo 缓存技巧、ALC 域加载策略、事件驱动架构等。\r
\r
## 扩展包说明\r
\r
Natasha 提供了多个官方扩展包,按需引入:\r
\r
| 扩展包 | 用途 | NuGet |\r
|--------|------|-------|\r
| `DotNetCore.Natasha.CSharp.Extension.MethodCreator` | 动态委托生成,最简洁的 `ToFunc\x3CT>()` API | 封装了动态方法创建的简化流程 |\r
| `DotNetCore.Natasha.CSharp.Extension.CompileDirector` | 编译"学习"机制,自适应优化 using code | 适合重复编译相似脚本 |\r
| `DotNetCore.Natasha.CSharp.Extension.HotReload` | 热重载支持 | 运行时更新代码 |\r
| `DotNetCore.Natasha.CSharp.Extension.Codecov` | 代码覆盖率支持 | 测试场景 |\r
\r
## API 设计规范\r
\r
Natasha 的 API 遵循严格的命名规范,理解它们能帮助你快速找到需要的 API:\r
\r
| 系列 | 语义 | 示例 |\r
|------|------|------|\r
| **With** | 条件开关/附加值 | `WithSmartMode()`, `WithPrivateAccess()`, `WithDebugCompile()` |\r
| **Set** | 单向赋值 | `SetAssemblyName()`, `SetDllFilePath()` |\r
| **Config** | 组件深入配置 | `ConfigCompilerOption(opt=>...)`, `ConfigSyntaxOptions(opt=>...)` |\r
| **Use** | 核心行为选择 | `UseRandomLoadContext()`, `UseSmartMode()`, `UseSimpleMode()` |\r
| **Add** | 添加内容 | `Add(code)`, `AddReferenceAndUsingCode(type)` |\r
| **Get** | 获取结果 | `GetAssembly()`, `GetTypeFromShortName()` |\r
\r
> **提示:** 如果你找不到 API,先确定你要做什么(开关?赋值?配置?),然后去找对应的 With/Set/Config 系列。\r
- 确保已安装 OpenClaw(本地或 Docker 部署)
- 在对话框中输入安装命令:
/install csharp-dotnetcore-natasha - 安装完成后,直接呼叫该 Skill 的名称或使用
/csharp-dotnetcore-natasha触发 - 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
Csharp Dotnetcore Natasha 是什么?
This skill should be used when developers need to create dynamic C# features at runtime, including dynamic class generation, dynamic method creation, accessi... 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 123 次。
如何安装 Csharp Dotnetcore Natasha?
在 OpenClaw 或 Claude Code 对话框中运行命令「/install csharp-dotnetcore-natasha」即可一键安装,无需额外配置。
Csharp Dotnetcore Natasha 是免费的吗?
是的,Csharp Dotnetcore Natasha 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。
Csharp Dotnetcore Natasha 支持哪些平台?
Csharp Dotnetcore Natasha 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。
谁开发了 Csharp Dotnetcore Natasha?
由 NMSAzulXXiaoHao(@nmsazulxxiaohao)开发并维护,当前版本 v3.3.0。