| 组件 | 要求 |
|---|---|
| 运行时 | .NET 8.0 (SDK or Runtime) |
| 目标框架 | net8.0 |
| IDE | VS2022 / Rider / VS Code + C# |
| 项目类型 | Class Library |
| 程序集名称 | 必须为 Main |
Main,否则主程序找不到 Main.dll,插件被跳过。<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<AssemblyName>Main</AssemblyName> <!-- ★ 固定 ★ -->
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<ItemGroup>
<Reference Include="ConverterPlugins">
<HintPath>..\CYLDConverterDev\ConverterPlugins.dll</HintPath>
<Private>false</Private> <!-- 禁止复制到输出目录 -->
</Reference>
</ItemGroup>
</Project>
插件主类必须实现 IConverterPlugin,并提供以下成员:
public interface IConverterPlugin
{
string PluginName { get; } // 唯一名称
string PluginInfo { get; }
string Author { get; }
string Version { get; }
string DetailedDescription { get; }
string CreatedTime { get; }
string[] SupportedInputExtensions { get; } // 如 new[] { ".litematic" }
string SupportedOutputExtension { get; } // 如 ".schem"
bool Convert(object inputData, string outputPath,
string pluginDirectory, object? options);
}
📌 可选接口 IPluginOptionsProvider:用于动态询问用户参数,返回 List<PluginOption>,主程序自动收集并传入 options 字典。
public List<PluginOption>? GetOptions() => new()
{
new PluginOption { Key = "scale", DisplayName = "缩放比例", ValueType = "float", DefaultValue = "1.0" }
};ConverterPlugins.dll 或 Newtonsoft.Json.dll 放入插件目录!<Private>false</Private> 或 ExcludeAssets="runtime"。
插件可能需要共享映射表或配置文件。为避免路径硬编码,请实现以下辅助函数(按优先级搜索插件目录 → out子目录 → Plugins根目录):
private static string? FindResourceFile(string pluginDir, string fileName)
{
string path = Path.Combine(pluginDir, fileName);
if (File.Exists(path)) return path;
path = Path.Combine(pluginDir, "out", fileName);
if (File.Exists(path)) return path;
string? parent = Path.GetDirectoryName(pluginDir);
if (parent != null)
{
path = Path.Combine(parent, fileName);
if (File.Exists(path)) return path;
}
return null;
}主程序通过 options 参数传入进度回调,插件可在转换过程中调用 reportProgress?.Invoke(percent) 显示进度条。
public bool Convert(object inputData, string outputPath, string pluginDirectory, object? options)
{
Action<int>? progress = null;
if (options is Action<int> direct) progress = direct;
else if (options is Dictionary<string,object> dict && dict.TryGetValue("__progress__", out var cb) && cb is Action<int> act)
progress = act;
progress?.Invoke(0);
// ... 业务逻辑
progress?.Invoke(100);
return true;
}using System.Text;
using ConverterPlugins;
public class LineNumberConverter : IConverterPlugin, IPluginOptionsProvider
{
public string PluginName => "行号添加器";
public string PluginInfo => "为文本每行加行号";
public string Author => "示例";
public string Version => "1.0";
public string DetailedDescription => "支持自定义分隔符和起始行号";
public string[] SupportedInputExtensions => new[] { ".txt", ".log" };
public string SupportedOutputExtension => ".txt";
public string CreatedTime => "2026";
public List<PluginOption>? GetOptions() => new()
{
new() { Key = "separator", DisplayName = "分隔符", ValueType = "string", DefaultValue = ": " },
new() { Key = "startLine", DisplayName = "起始行号", ValueType = "int", DefaultValue = "1" }
};
public bool Convert(object inputData, string outputPath, string pluginDirectory, object? options)
{
if (inputData is not byte[] bytes) return false;
var opts = options as Dictionary<string, object> ?? new();
string sep = opts.GetValueOrDefault("separator") as string ?? ": ";
int start = opts.GetValueOrDefault("startLine") is int s ? s : 1;
string text = Encoding.UTF8.GetString(bytes);
var lines = text.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
var sb = new StringBuilder();
for (int i = 0; i < lines.Length; i++)
sb.Append(start + i).Append(sep).AppendLine(lines[i]);
File.WriteAllText(outputPath, sb.ToString(), Encoding.UTF8);
return true;
}
}CYLDConverterDev/ ├── CYLDConverterDev.exe ├── ConverterPlugins.dll (主程序提供,切勿复制到插件文件夹) ├── Plugins/ │ ├── MyPlugin/ (任意插件名) │ │ └── Main.dll ★ 必须 Main.dll │ ├── LitematicConverter/ │ │ └── Main.dll │ └── shared_mappings.json (共享资源,可由 FindResourceFile 定位) └── Logs/
dotnet build -c Releasebin/Release/net8.0/Main.dll 覆盖到 Plugins/你的插件/| 现象 | 原因 | 解决 |
|---|---|---|
| 跳过: XXX (缺少 Main.dll) | 程序集输出不是 Main.dll | 修改 .csproj 添加 <AssemblyName>Main</AssemblyName> |
| 类型冲突 / 接口不存在 | 插件目录包含了 ConverterPlugins.dll | 删除多余dll,引用的HintPath设置Private=false |
| 重复插件名称,跳过 | 两个插件的 PluginName 相同 | 确保每个插件唯一名称 |
| 依赖库 FileNotFoundException | 第三方dll未放入插件目录 | 复制依赖到插件子目录 |
| 资源文件找不到 | 未使用 FindResourceFile | 采用第5节的搜索逻辑 |
日志查看目录:Logs/CYLDConverterDev_日期.log,开发版日志级别为 DEBUG。
Main.dll.sig (XOR 加密)。Plugins/插件名/ 目录,必须包含 Main.dll + Main.dll.sig + 依赖。using ConverterPlugins;
namespace MyNamespace;
public class MyConverter : IConverterPlugin
{
public string PluginName => "示例转换器";
public string PluginInfo => "描述信息";
public string Author => "YourName";
public string Version => "1.0";
public string DetailedDescription => "完整功能描述";
public string CreatedTime => DateTime.Now.ToString("yyyy-MM-dd");
public string[] SupportedInputExtensions => new[] { ".dat" };
public string SupportedOutputExtension => ".txt";
public bool Convert(object inputData, string outputPath, string pluginDirectory, object? options)
{
if (inputData is not byte[] bytes) return false;
File.WriteAllBytes(outputPath, bytes); // 示例逻辑
return true;
}
}$plugin="MyPlugin"; $dest="CYLDConverterDev/Plugins/$plugin" dotnet build -c Release; Copy-Item "bin/Release/net8.0/Main.dll" "$dest/Main.dll" -Force Write-Host "部署完成,按主程序 [3] 热重载" -Foreground Green