Shell、Process与脚本引擎:C# .NET企业级实现

一、系统架构设计与UML建模

1.1 整体架构设计

uses

uses

uses

creates

manages

contains

uses

DotNetShell

-prompt: string

-history: List<string>

-environment: Dictionary<string, string>

-aliases: Dictionary<string, string>

-processManager: ProcessManager

-commandParser: CommandParser

-scriptEngine: MultiScriptEngine

-isRunning: bool

+RunAsync() : Task

+ExecuteCommandAsync(cmd: string) : Task<int>

+SetEnvironmentVariable(key: string, value: string)

+GetEnvironmentVariable(key: string) : string

ProcessManager

-processes: ConcurrentDictionary<int, ProcessInfo>

-jobs: ConcurrentDictionary<int, JobInfo>

-processStartLock: SemaphoreSlim

+CreateProcessAsync(cmd: ParsedCommand) : Task<Process>

+CreatePipelineAsync(commands: List<ParsedCommand>) : Task<List<Process>>

+WaitForProcessAsync(pid: int) : Task<int>

+KillProcessAsync(pid: int, force: bool) : Task<bool>

+GetProcesses() : List<ProcessInfo>

MultiScriptEngine

-engines: ConcurrentDictionary<string, IScriptExecutor>

-sandbox: ScriptSandbox

-assemblyLoader: AssemblyLoader

+RegisterExecutor(language: string, executor: IScriptExecutor)

+EvaluateAsync(language: string, code: string, context: ScriptContext) : Task<object>

+ExecuteFileAsync(filePath: string) : Task<object>

+CompileAsync(language: string, code: string) : Task<CompiledScript>

«interface»

IScriptExecutor

+LanguageName: string

+FileExtensions: string[]

+ExecuteAsync(code: string, context: ScriptContext) : Task<object>

+ExecuteFileAsync(filePath: string, context: ScriptContext) : Task<object>

+CompileAsync(code: string) : Task<CompiledScript>

CommandParser

+Parse(input: string) : ParsedCommand

-Tokenize(input: string) : List<string>

-ParseTokens(tokens: List<string>) : ParsedCommand

-ExpandVariables(input: string) : string

ParsedCommand

+Args: List<string>

+StdIn: string

+StdOut: string

+StdErr: string

+Append: bool

+Background: bool

+Piped: bool

+Next: ParsedCommand

+EnvironmentVariables: Dictionary<string, string>

+WorkingDirectory: string

ProcessInfo

+Id: int

+Name: string

+CommandLine: string

+StartTime: DateTime

+ExitTime: DateTime?

+ExitCode: int?

+Status: ProcessStatus

+JobId: int?

ScriptContext

+Environment: Dictionary<string, string>

+WorkingDirectory: string

+Arguments: List<string>

+Shell: IShellContext

+SecurityPolicy: SecurityPolicy

1.2 核心交互序列图

.NET Runtime IScriptExecutor MultiScriptEngine ProcessManager CommandExecutor CommandParser DotNetShell User .NET Runtime IScriptExecutor MultiScriptEngine ProcessManager CommandExecutor CommandParser DotNetShell User par [并行等待] alt [是内置命令] [是脚本命令] [是外部命令] 输入 "Get-ChildItem | Select-String '.cs'" Parse(input) ParsedCommand ExecuteBuiltin(parsedCmd) 退出码 EvaluateAsync("powershell", code, context) ExecuteAsync(code, context) 执行结果 结果对象 CreatePipelineAsync([cmd1, cmd2]) Process.Start(cmd1) Process对象 Process.Start(cmd2) Process对象 连接管道 WaitForExitAsync(process1) WaitForExitAsync(process2) 退出码 最终退出码 显示输出/结果

1.3 三者的关系与区别

维度 Shell Process 脚本引擎
本质 命令行解释器(.NET应用程序) 操作系统进程实例 语言解释器/编译器
职责 用户交互、命令分发、环境管理 执行程序、管理资源 解析、编译、执行脚本
创建方式 Main方法启动 Process.Start() 引擎工厂创建
生命周期 用户会话期间 程序执行期间 脚本执行期间
资源管理 管理线程池、连接池、缓存 管理句柄、内存、线程 管理符号表、JIT编译、垃圾回收
通信机制 标准I/O、管道、消息队列 IPC、管道、共享内存 API调用、委托、动态绑定
.NET实现 封装Process类、并发集合 Process/ProcessStartInfo Roslyn、DLR、动态编译

二、C# .NET完整实现

2.1 项目结构与解决方案

<!-- DotNetShell.csproj -->
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  </PropertyGroup>
  
  <ItemGroup>
    <!-- 脚本引擎依赖 -->
    <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.9.2" />
    <PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.Scripting" Version="4.9.2" />
    <PackageReference Include="IronPython" Version="3.4.1" />
    <PackageReference Include="IronRuby" Version="1.1.4" />
    <PackageReference Include="NLua" Version="1.6.2" />
    <PackageReference Include="Jint" Version="3.0.0" />
    <PackageReference Include="ClearScript" Version="7.4.5" />
    <PackageReference Include="PowerShell" Version="7.4.1" />
    
    <!-- 工具库 -->
    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
    <PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
    <PackageReference Include="Spectre.Console" Version="0.48.0" />
    <PackageReference Include="System.CommandLine" Version="2.0.0" />
    
    <!-- WebAssembly支持 -->
    <PackageReference Include="Wasmtime" Version="14.0.0" />
    
    <!-- 测试 -->
    <PackageReference Include="xunit" Version="2.7.0" />
    <PackageReference Include="Moq" Version="4.20.70" />
  </ItemGroup>
</Project>

2.2 公共类型定义

// DotNetShell.Core/Types/CommandTypes.cs
namespace DotNetShell.Core.Types
{
    public class ParsedCommand
    {
        public string RawCommand { get; set; } = string.Empty;
        public List<string> Arguments { get; set; } = new();
        public string StandardInput { get; set; } = string.Empty;
        public string StandardOutput { get; set; } = string.Empty;
        public string StandardError { get; set; } = string.Empty;
        public bool AppendOutput { get; set; }
        public bool RunInBackground { get; set; }
        public bool IsPiped { get; set; }
        public ParsedCommand? NextCommand { get; set; }
        public Dictionary<string, string> EnvironmentVariables { get; set; } = new();
        public string WorkingDirectory { get; set; } = string.Empty;
        
        public bool IsBuiltin => Arguments.Count > 0 && 
            BuiltinCommandRegistry.IsBuiltin(Arguments[0]);
    }
    
    public enum ProcessStatus
    {
        Running,
        Suspended,
        Exited,
        Terminated
    }
    
    public class ProcessInfo
    {
        public int Id { get; set; }
        public int ParentId { get; set; }
        public string Name { get; set; } = string.Empty;
        public string CommandLine { get; set; } = string.Empty;
        public ProcessStatus Status { get; set; }
        public DateTime StartTime { get; set; }
        public DateTime? ExitTime { get; set; }
        public int? ExitCode { get; set; }
        public int? JobId { get; set; }
        public string WorkingDirectory { get; set; } = string.Empty;
        public Dictionary<string, string> Environment { get; set; } = new();
    }
    
    public class ScriptResult
    {
        public bool Success { get; set; }
        public object? Value { get; set; }
        public string Error { get; set; } = string.Empty;
        public TimeSpan ExecutionTime { get; set; }
        public string Language { get; set; } = string.Empty;
    }
    
    public class ScriptContext
    {
        public Dictionary<string, string> Environment { get; set; } = new();
        public string WorkingDirectory { get; set; } = string.Empty;
        public List<string> Arguments { get; set; } = new();
        public IShellContext? Shell { get; set; }
        public SecurityPolicy SecurityPolicy { get; set; } = new();
        
        public class SecurityPolicy
        {
            public bool AllowFileSystemAccess { get; set; } = true;
            public bool AllowNetworkAccess { get; set; } = false;
            public bool AllowReflection { get; set; } = false;
            public bool AllowNativeCode { get; set; } = false;
            public List<string> AllowedAssemblies { get; set; } = new();
            public List<string> AllowedNamespaces { get; set; } = new();
            public long MaxMemoryBytes { get; set; } = 100 * 1024 * 1024; // 100MB
            public TimeSpan ExecutionTimeout { get; set; } = TimeSpan.FromSeconds(30);
        }
    }
    
    public class ShellConfiguration
    {
        public string Prompt { get; set; } = "dsh> ";
        public string HistoryFilePath { get; set; } = "~/.dnsh_history";
        public int HistorySize { get; set; } = 1000;
        public bool EnableColors { get; set; } = true;
        public bool EnableCompletion { get; set; } = true;
        public int MaxProcesses { get; set; } = 100;
        public TimeSpan ExecutionTimeout { get; set; } = TimeSpan.FromSeconds(30);
        public string InitScriptPath { get; set; } = "~/.dnshrc";
        public string DefaultScriptLanguage { get; set; } = "csharp";
        
        public static ShellConfiguration Default => new();
    }
}

2.3 Shell核心实现

// DotNetShell/Shell/DotNetShell.cs
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using DotNetShell.Core.Types;
using DotNetShell.Process;
using DotNetShell.Scripting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Spectre.Console;

namespace DotNetShell.Shell
{
    public interface IShellContext
    {
        string CurrentDirectory { get; }
        Dictionary<string, string> EnvironmentVariables { get; }
        void WriteLine(string text, ConsoleColor? color = null);
        void WriteError(string message);
        Task<int> ExecuteCommandAsync(string command);
    }
    
    public class DotNetShell : IShellContext, IAsyncDisposable
    {
        private readonly ShellConfiguration _configuration;
        private readonly ILogger<DotNetShell> _logger;
        private readonly ProcessManager _processManager;
        private readonly CommandParser _commandParser;
        private readonly MultiScriptEngine _scriptEngine;
        private readonly ConcurrentDictionary<string, string> _environment;
        private readonly ConcurrentDictionary<string, string> _aliases;
        private readonly List<string> _history;
        private readonly Dictionary<string, IBuiltinCommand> _builtins;
        private readonly CancellationTokenSource _cancellationTokenSource;
        private readonly IServiceProvider _serviceProvider;
        
        private volatile bool _isRunning;
        private int _lastExitCode;
        private string _currentDirectory;
        
        public event EventHandler<CommandExecutedEventArgs>? CommandExecuted;
        public event EventHandler<CommandErrorEventArgs>? CommandError;
        public event EventHandler? ShellStarted;
        public event EventHandler? ShellStopping;
        
        public DotNetShell(ShellConfiguration? configuration = null,
                          ILogger<DotNetShell>? logger = null,
                          IServiceProvider? serviceProvider = null)
        {
            _configuration = configuration ?? ShellConfiguration.Default;
            _logger = logger ?? CreateDefaultLogger();
            _serviceProvider = serviceProvider ?? CreateServiceProvider();
            
            _environment = new ConcurrentDictionary<string, string>(
                StringComparer.OrdinalIgnoreCase);
            _aliases = new ConcurrentDictionary<string, string>(
                StringComparer.OrdinalIgnoreCase);
            _history = new List<string>();
            _builtins = new Dictionary<string, IBuiltinCommand>(
                StringComparer.OrdinalIgnoreCase);
            _cancellationTokenSource = new CancellationTokenSource();
            
            _processManager = new ProcessManager(_configuration.MaxProcesses);
            _commandParser = new CommandParser();
            _scriptEngine = new MultiScriptEngine(this);
            
            Initialize();
        }
        
        private void Initialize()
        {
            // 初始化环境变量
            InitializeEnvironment();
            
            // 初始化内置命令
            InitializeBuiltins();
            
            // 初始化脚本引擎
            InitializeScriptEngines();
            
            // 设置当前目录
            _currentDirectory = Directory.GetCurrentDirectory();
            _environment["PWD"] = _currentDirectory;
            
            // 设置控制台
            Console.OutputEncoding = Encoding.UTF8;
            Console.InputEncoding = Encoding.UTF8;
            Console.CancelKeyPress += OnConsoleCancelKeyPress;
        }
        
        private void InitializeEnvironment()
        {
            // 从父进程继承环境变量
            foreach (DictionaryEntry entry in Environment.GetEnvironmentVariables())
            {
                if (entry.Key is string key && entry.Value is string value)
                {
                    _environment[key] = value;
                }
            }
            
            // 设置Shell特定环境变量
            _environment["SHELL"] = "DotNetShell";
            _environment["TERM"] = Environment.GetEnvironmentVariable("TERM") ?? "xterm-256color";
            _environment["HOME"] = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
            _environment["USER"] = Environment.UserName;
            _environment["HOST"] = Environment.MachineName;
        }
        
        private void InitializeBuiltins()
        {
            // 注册内置命令
            _builtins["cd"] = new ChangeDirectoryCommand();
            _builtins["chdir"] = _builtins["cd"];
            
            _builtins["dir"] = new DirectoryListingCommand();
            _builtins["ls"] = _builtins["dir"];
            
            _builtins["type"] = new TypeFileCommand();
            _builtins["cat"] = _builtins["type"];
            
            _builtins["copy"] = new CopyFileCommand();
            _builtins["cp"] = _builtins["copy"];
            
            _builtins["move"] = new MoveFileCommand();
            _builtins["mv"] = _builtins["move"];
            
            _builtins["del"] = new DeleteFileCommand();
            _builtins["rm"] = _builtins["del"];
            
            _builtins["mkdir"] = new CreateDirectoryCommand();
            _builtins["md"] = _builtins["mkdir"];
            
            _builtins["rmdir"] = new RemoveDirectoryCommand();
            _builtins["rd"] = _builtins["rmdir"];
            
            _builtins["echo"] = new EchoCommand();
            _builtins["print"] = _builtins["echo"];
            
            _builtins["set"] = new SetEnvironmentVariableCommand();
            _builtins["export"] = _builtins["set"];
            
            _builtins["alias"] = new AliasCommand();
            _builtins["unalias"] = new UnaliasCommand();
            
            _builtins["history"] = new HistoryCommand();
            _builtins["jobs"] = new JobsCommand();
            
            _builtins["fg"] = new ForegroundJobCommand();
            _builtins["bg"] = new BackgroundJobCommand();
            
            _builtins["kill"] = new KillCommand();
            _builtins["ps"] = new ProcessListCommand();
            
            _builtins["cls"] = new ClearScreenCommand();
            _builtins["clear"] = _builtins["cls"];
            
            _builtins["help"] = new HelpCommand();
            _builtins["?"] = _builtins["help"];
            
            _builtins["exit"] = new ExitCommand();
            _builtins["quit"] = _builtins["exit"];
            
            _builtins["source"] = new SourceCommand();
            _builtins["."] = _builtins["source"];
        }
        
        private void InitializeScriptEngines()
        {
            // 注册各种脚本引擎
            _scriptEngine.RegisterExecutor("csharp", new CSharpScriptExecutor(this));
            _scriptEngine.RegisterExecutor("vb", new VisualBasicScriptExecutor(this));
            _scriptEngine.RegisterExecutor("powershell", new PowerShellExecutor(this));
            _scriptEngine.RegisterExecutor("python", new PythonExecutor(this));
            _scriptEngine.RegisterExecutor("ruby", new RubyExecutor(this));
            _scriptEngine.RegisterExecutor("lua", new LuaExecutor(this));
            _scriptEngine.RegisterExecutor("javascript", new JavaScriptExecutor(this));
            _scriptEngine.RegisterExecutor("typescript", new TypeScriptExecutor(this));
            // 更多引擎...
        }
        
        public async Task RunAsync()
        {
            if (_isRunning)
                throw new InvalidOperationException("Shell is already running");
            
            _isRunning = true;
            ShellStarted?.Invoke(this, EventArgs.Empty);
            
            // 显示欢迎信息
            WriteLine("DotNetShell v1.0.0 - Enterprise Multi-language Shell", ConsoleColor.Cyan);
            WriteLine("Type 'help' for available commands", ConsoleColor.DarkGray);
            WriteLine(string.Empty);
            
            // 加载初始化脚本
            await LoadInitScriptAsync();
            
            // 主循环
            while (_isRunning && !_cancellationTokenSource.Token.IsCancellationRequested)
            {
                try
                {
                    await ProcessInputAsync();
                }
                catch (OperationCanceledException)
                {
                    // 正常取消
                    break;
                }
                catch (Exception ex)
                {
                    WriteError($"Shell error: {ex.Message}");
                    _logger.LogError(ex, "Error in shell main loop");
                }
            }
            
            await StopAsync();
        }
        
        private async Task ProcessInputAsync()
        {
            // 读取输入
            string input = await ReadLineAsync();
            
            if (string.IsNullOrWhiteSpace(input))
                return;
            
            // 添加到历史记录
            _history.Add(input);
            if (_history.Count > _configuration.HistorySize)
                _history.RemoveAt(0);
            
            // 执行命令
            int exitCode = await ExecuteCommandAsync(input);
            
            // 更新最后退出码和环境变量
            _lastExitCode = exitCode;
            _environment["ERRORLEVEL"] = exitCode.ToString();
            _environment["?"] = exitCode.ToString();
        }
        
        private async Task<string> ReadLineAsync()
        {
            if (_configuration.EnableCompletion)
            {
                // 使用Spectre.Console提供更好的交互体验
                return await AnsiConsole.PromptAsync(
                    new TextPrompt<string>(_configuration.Prompt)
                        .PromptStyle("green")
                        .AllowEmpty()
                        .AddChoice("exit")
                        .AddChoice("help")
                        .AddChoice("clear")
                );
            }
            else
            {
                Console.Write(_configuration.Prompt);
                return Console.ReadLine() ?? string.Empty;
            }
        }
        
        public async Task<int> ExecuteCommandAsync(string command)
        {
            if (string.IsNullOrWhiteSpace(command))
                return 0;
            
            var stopwatch = Stopwatch.StartNew();
            
            try
            {
                // 检查是否是脚本模式
                if (IsScriptMode(command, out string language, out string code))
                {
                    return await ExecuteScriptCodeAsync(language, code);
                }
                
                // 扩展别名
                command = ExpandAliases(command);
                
                // 扩展环境变量
                command = ExpandEnvironmentVariables(command);
                
                // 解析命令
                ParsedCommand parsedCommand = _commandParser.Parse(command, _environment);
                
                // 检查是否是内置命令
                if (parsedCommand.IsBuiltin)
                {
                    return await ExecuteBuiltinCommandAsync(parsedCommand);
                }
                
                // 检查是否是脚本文件
                if (IsScriptFile(parsedCommand.Arguments[0]))
                {
                    return await ExecuteScriptFileAsync(parsedCommand);
                }
                
                // 执行外部命令
                return await ExecuteExternalCommandAsync(parsedCommand);
            }
            catch (Exception ex)
            {
                WriteError($"Command execution failed: {ex.Message}");
                CommandError?.Invoke(this, new CommandErrorEventArgs
                {
                    Command = command,
                    Error = ex.Message,
                    Timestamp = DateTime.UtcNow
                });
                return 1;
            }
            finally
            {
                stopwatch.Stop();
                _logger.LogDebug("Command executed in {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
            }
        }
        
        private bool IsScriptMode(string command, out string language, out string code)
        {
            language = string.Empty;
            code = string.Empty;
            
            // 检查是否是指定语言的脚本
            foreach (var lang in _scriptEngine.GetSupportedLanguages())
            {
                string prefix = lang + ">";
                if (command.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
                {
                    language = lang;
                    code = command[prefix.Length..].TrimStart();
                    return true;
                }
            }
            
            return false;
        }
        
        private async Task<int> ExecuteScriptCodeAsync(string language, string code)
        {
            try
            {
                var context = new ScriptContext
                {
                    Environment = new Dictionary<string, string>(_environment),
                    WorkingDirectory = _currentDirectory,
                    Shell = this,
                    SecurityPolicy = new ScriptContext.SecurityPolicy
                    {
                        ExecutionTimeout = _configuration.ExecutionTimeout
                    }
                };
                
                object? result = await _scriptEngine.EvaluateAsync(language, code, context);
                
                if (result != null)
                {
                    WriteLine(result.ToString() ?? string.Empty);
                }
                
                return 0;
            }
            catch (Exception ex)
            {
                WriteError($"Script error: {ex.Message}");
                return 1;
            }
        }
        
        private string ExpandAliases(string command)
        {
            string[] parts = command.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries);
            if (parts.Length > 0 && _aliases.TryGetValue(parts[0], out string? alias))
            {
                return alias + (parts.Length > 1 ? " " + parts[1] : "");
            }
            return command;
        }
        
        private string ExpandEnvironmentVariables(string command)
        {
            string result = command;
            
            foreach (var kvp in _environment)
            {
                result = result.Replace($"${kvp.Key}", kvp.Value)
                              .Replace($"${{{kvp.Key}}}", kvp.Value)
                              .Replace($"%{kvp.Key}%", kvp.Value);
            }
            
            return result;
        }
        
        private async Task<int> ExecuteBuiltinCommandAsync(ParsedCommand command)
        {
            string commandName = command.Arguments[0];
            
            if (_builtins.TryGetValue(commandName, out IBuiltinCommand? builtin))
            {
                var args = command.Arguments.Skip(1).ToList();
                return await builtin.ExecuteAsync(args, this);
            }
            
            WriteError($"Builtin command not found: {commandName}");
            return 1;
        }
        
        private bool IsScriptFile(string path)
        {
            if (string.IsNullOrEmpty(path))
                return false;
            
            string extension = Path.GetExtension(path).ToLowerInvariant();
            
            return extension switch
            {
                ".cs" => true,
                ".vb" => true,
                ".ps1" => true,
                ".py" => true,
                ".rb" => true,
                ".lua" => true,
                ".js" => true,
                ".ts" => true,
                _ => false
            };
        }
        
        private async Task<int> ExecuteScriptFileAsync(ParsedCommand command)
        {
            string filePath = Path.Combine(_currentDirectory, command.Arguments[0]);
            
            if (!File.Exists(filePath))
            {
                WriteError($"Script file not found: {filePath}");
                return 1;
            }
            
            string extension = Path.GetExtension(filePath).ToLowerInvariant();
            string language = extension switch
            {
                ".cs" => "csharp",
                ".vb" => "vb",
                ".ps1" => "powershell",
                ".py" => "python",
                ".rb" => "ruby",
                ".lua" => "lua",
                ".js" => "javascript",
                ".ts" => "typescript",
                _ => throw new NotSupportedException($"Unsupported script extension: {extension}")
            };
            
            try
            {
                var context = new ScriptContext
                {
                    Environment = new Dictionary<string, string>(_environment),
                    WorkingDirectory = _currentDirectory,
                    Arguments = command.Arguments.Skip(1).ToList(),
                    Shell = this,
                    SecurityPolicy = new ScriptContext.SecurityPolicy
                    {
                        ExecutionTimeout = _configuration.ExecutionTimeout
                    }
                };
                
                object? result = await _scriptEngine.ExecuteFileAsync(language, filePath, context);
                
                if (result != null)
                {
                    WriteLine(result.ToString() ?? string.Empty);
                }
                
                return 0;
            }
            catch (Exception ex)
            {
                WriteError($"Script execution failed: {ex.Message}");
                return 1;
            }
        }
        
        private async Task<int> ExecuteExternalCommandAsync(ParsedCommand command)
        {
            if (command.IsPiped && command.NextCommand != null)
            {
                // 管道命令
                var commands = new List<ParsedCommand>();
                ParsedCommand? current = command;
                
                while (current != null)
                {
                    commands.Add(current);
                    current = current.NextCommand;
                }
                
                var processes = await _processManager.CreatePipelineAsync(commands);
                
                // 等待所有进程完成
                int exitCode = 0;
                foreach (var process in processes)
                {
                    exitCode = await _processManager.WaitForProcessAsync(process.Id);
                }
                
                return exitCode;
            }
            else
            {
                // 单个命令
                var process = await _processManager.CreateProcessAsync(command);
                
                if (command.RunInBackground)
                {
                    WriteLine($"[{process.Id}] {command.RawCommand}", ConsoleColor.DarkGray);
                    return 0;
                }
                else
                {
                    return await _processManager.WaitForProcessAsync(process.Id);
                }
            }
        }
        
        private async Task LoadInitScriptAsync()
        {
            string initScriptPath = _configuration.InitScriptPath.Replace("~", 
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile));
            
            if (File.Exists(initScriptPath))
            {
                try
                {
                    string[] lines = await File.ReadAllLinesAsync(initScriptPath);
                    
                    foreach (string line in lines)
                    {
                        string trimmed = line.Trim();
                        if (!string.IsNullOrEmpty(trimmed) && !trimmed.StartsWith('#'))
                        {
                            await ExecuteCommandAsync(trimmed);
                        }
                    }
                }
                catch (Exception ex)
                {
                    WriteError($"Failed to load init script: {ex.Message}");
                }
            }
        }
        
        public async Task StopAsync()
        {
            if (!_isRunning)
                return;
            
            ShellStopping?.Invoke(this, EventArgs.Empty);
            
            _isRunning = false;
            _cancellationTokenSource.Cancel();
            
            // 清理资源
            await _processManager.DisposeAsync();
            await _scriptEngine.DisposeAsync();
            
            // 保存历史记录
            await SaveHistoryAsync();
            
            Console.CancelKeyPress -= OnConsoleCancelKeyPress;
        }
        
        private async Task SaveHistoryAsync()
        {
            try
            {
                string historyPath = _configuration.HistoryFilePath.Replace("~",
                    Environment.GetFolderPath(Environment.SpecialFolder.UserProfile));
                
                string directory = Path.GetDirectoryName(historyPath)!;
                if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }
                
                await File.WriteAllLinesAsync(historyPath, _history);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to save history");
            }
        }
        
        private void OnConsoleCancelKeyPress(object? sender, ConsoleCancelEventArgs e)
        {
            e.Cancel = true; // 阻止进程终止
            
            WriteLine("^C", ConsoleColor.Yellow);
            _processManager.KillForegroundProcess();
        }
        
        // IShellContext 实现
        public string CurrentDirectory => _currentDirectory;
        
        public Dictionary<string, string> EnvironmentVariables => 
            new Dictionary<string, string>(_environment);
        
        public void WriteLine(string text, ConsoleColor? color = null)
        {
            if (color.HasValue)
            {
                var oldColor = Console.ForegroundColor;
                Console.ForegroundColor = color.Value;
                Console.WriteLine(text);
                Console.ForegroundColor = oldColor;
            }
            else
            {
                Console.WriteLine(text);
            }
        }
        
        public void WriteError(string message)
        {
            WriteLine($"Error: {message}", ConsoleColor.Red);
        }
        
        // 内置命令接口
        public interface IBuiltinCommand
        {
            Task<int> ExecuteAsync(List<string> args, IShellContext shell);
        }
        
        // 内置命令实现示例
        public class ChangeDirectoryCommand : IBuiltinCommand
        {
            public async Task<int> ExecuteAsync(List<string> args, IShellContext shell)
            {
                string target = args.FirstOrDefault() ?? 
                    Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
                
                if (target == "-")
                {
                    // 切换到上一个目录
                    if (shell.EnvironmentVariables.TryGetValue("OLDPWD", out string? oldPwd))
                    {
                        target = oldPwd;
                    }
                    else
                    {
                        shell.WriteError("OLDPWD not set");
                        return 1;
                    }
                }
                
                try
                {
                    string oldDir = shell.CurrentDirectory;
                    string newDir = Path.GetFullPath(Path.Combine(shell.CurrentDirectory, target));
                    
                    Directory.SetCurrentDirectory(newDir);
                    
                    // 更新环境变量
                    shell.EnvironmentVariables["OLDPWD"] = oldDir;
                    shell.EnvironmentVariables["PWD"] = newDir;
                    
                    return 0;
                }
                catch (Exception ex)
                {
                    shell.WriteError($"cd: {target}: {ex.Message}");
                    return 1;
                }
            }
        }
        
        public class SourceCommand : IBuiltinCommand
        {
            public async Task<int> ExecuteAsync(List<string> args, IShellContext shell)
            {
                if (args.Count == 0)
                {
                    shell.WriteError("source: filename argument required");
                    return 1;
                }
                
                string filePath = Path.Combine(shell.CurrentDirectory, args[0]);
                
                if (!File.Exists(filePath))
                {
                    shell.WriteError($"source: file not found: {filePath}");
                    return 1;
                }
                
                try
                {
                    string[] lines = await File.ReadAllLinesAsync(filePath);
                    
                    foreach (string line in lines)
                    {
                        string trimmed = line.Trim();
                        if (!string.IsNullOrEmpty(trimmed) && !trimmed.StartsWith('#'))
                        {
                            await shell.ExecuteCommandAsync(trimmed);
                        }
                    }
                    
                    return 0;
                }
                catch (Exception ex)
                {
                    shell.WriteError($"source: {ex.Message}");
                    return 1;
                }
            }
        }
        
        // 其他内置命令实现...
        
        private static ILogger<DotNetShell> CreateDefaultLogger()
        {
            return LoggerFactory.Create(builder =>
            {
                builder.AddConsole();
                builder.SetMinimumLevel(LogLevel.Information);
            }).CreateLogger<DotNetShell>();
        }
        
        private static IServiceProvider CreateServiceProvider()
        {
            var services = new ServiceCollection();
            services.AddLogging();
            return services.BuildServiceProvider();
        }
        
        public async ValueTask DisposeAsync()
        {
            await StopAsync();
            _cancellationTokenSource.Dispose();
            GC.SuppressFinalize(this);
        }
    }
    
    // 事件参数类
    public class CommandExecutedEventArgs : EventArgs
    {
        public string Command { get; set; } = string.Empty;
        public int ExitCode { get; set; }
        public DateTime Timestamp { get; set; }
    }
    
    public class CommandErrorEventArgs : EventArgs
    {
        public string Command { get; set; } = string.Empty;
        public string Error { get; set; } = string.Empty;
        public DateTime Timestamp { get; set; }
    }
}

2.4 进程管理器实现

// DotNetShell/Process/ProcessManager.cs
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using DotNetShell.Core.Types;

namespace DotNetShell.Process
{
    public class ProcessManager : IAsyncDisposable
    {
        private readonly int _maxProcesses;
        private readonly ConcurrentDictionary<int, ProcessInfo> _processes;
        private readonly ConcurrentDictionary<int, JobInfo> _jobs;
        private readonly SemaphoreSlim _processLock;
        private readonly CancellationTokenSource _cancellationTokenSource;
        private readonly Task _monitorTask;
        private Process? _foregroundProcess;
        
        public ProcessManager(int maxProcesses = 100)
        {
            _maxProcesses = maxProcesses;
            _processes = new ConcurrentDictionary<int, ProcessInfo>();
            _jobs = new ConcurrentDictionary<int, JobInfo>();
            _processLock = new SemaphoreSlim(1, 1);
            _cancellationTokenSource = new CancellationTokenSource();
            _monitorTask = Task.Run(MonitorProcessesAsync);
        }
        
        public async Task<Process> CreateProcessAsync(ParsedCommand command)
        {
            await _processLock.WaitAsync();
            
            try
            {
                if (_processes.Count >= _maxProcesses)
                {
                    throw new InvalidOperationException(
                        $"Maximum number of processes ({_maxProcesses}) reached");
                }
                
                if (command.Arguments.Count == 0)
                {
                    throw new ArgumentException("No command specified");
                }
                
                var startInfo = new ProcessStartInfo
                {
                    FileName = command.Arguments[0],
                    Arguments = string.Join(" ", command.Arguments.Skip(1)),
                    UseShellExecute = false,
                    CreateNoWindow = true,
                    RedirectStandardInput = !string.IsNullOrEmpty(command.StandardInput),
                    RedirectStandardOutput = !string.IsNullOrEmpty(command.StandardOutput) || command.IsPiped,
                    RedirectStandardError = !string.IsNullOrEmpty(command.StandardError)
                };
                
                // 设置工作目录
                if (!string.IsNullOrEmpty(command.WorkingDirectory))
                {
                    startInfo.WorkingDirectory = command.WorkingDirectory;
                }
                
                // 设置环境变量
                foreach (var kvp in command.EnvironmentVariables)
                {
                    startInfo.EnvironmentVariables[kvp.Key] = kvp.Value;
                }
                
                // 创建进程
                var process = new Process
                {
                    StartInfo = startInfo,
                    EnableRaisingEvents = true
                };
                
                // 设置标准输入重定向
                if (!string.IsNullOrEmpty(command.StandardInput))
                {
                    if (command.StandardInput == "/dev/null" || 
                        command.StandardInput == "NUL")
                    {
                        process.StartInfo.RedirectStandardInput = false;
                        process.StartInfo.StandardInputEncoding = null;
                    }
                    else if (File.Exists(command.StandardInput))
                    {
                        process.StartInfo.RedirectStandardInput = true;
                    }
                }
                
                // 启动进程
                if (!process.Start())
                {
                    throw new InvalidOperationException($"Failed to start process: {command.Arguments[0]}");
                }
                
                // 设置输出重定向文件
                if (!string.IsNullOrEmpty(command.StandardOutput))
                {
                    var outputFile = new FileStream(command.StandardOutput,
                        command.AppendOutput ? FileMode.Append : FileMode.Create,
                        FileAccess.Write);
                    
                    process.StandardOutput.BaseStream.CopyToAsync(outputFile);
                }
                
                if (!string.IsNullOrEmpty(command.StandardError))
                {
                    var errorFile = new FileStream(command.StandardError,
                        command.AppendOutput ? FileMode.Append : FileMode.Create,
                        FileAccess.Write);
                    
                    process.StandardError.BaseStream.CopyToAsync(errorFile);
                }
                
                // 创建进程信息
                var processInfo = new ProcessInfo
                {
                    Id = process.Id,
                    ParentId = System.Diagnostics.Process.GetCurrentProcess().Id,
                    Name = Path.GetFileName(command.Arguments[0]),
                    CommandLine = $"{command.Arguments[0]} {string.Join(" ", command.Arguments.Skip(1))}",
                    Status = Types.ProcessStatus.Running,
                    StartTime = DateTime.Now,
                    WorkingDirectory = startInfo.WorkingDirectory,
                    Environment = new Dictionary<string, string>(command.EnvironmentVariables)
                };
                
                _processes[process.Id] = processInfo;
                
                // 如果是后台进程,创建作业
                if (command.RunInBackground)
                {
                    int jobId = _jobs.Count + 1;
                    var jobInfo = new JobInfo
                    {
                        Id = jobId,
                        ProcessIds = new List<int> { process.Id },
                        Command = command.RawCommand,
                        Status = JobStatus.Running
                    };
                    
                    _jobs[jobId] = jobInfo;
                    processInfo.JobId = jobId;
                    
                    // 分离进程
                    process.Exited += (sender, e) => OnProcessExited(process, jobId);
                }
                else
                {
                    _foregroundProcess = process;
                }
                
                // 监听进程退出
                process.Exited += (sender, e) => OnProcessExited(process, null);
                
                return process;
            }
            finally
            {
                _processLock.Release();
            }
        }
        
        public async Task<List<Process>> CreatePipelineAsync(List<ParsedCommand> commands)
        {
            if (commands.Count == 0)
                throw new ArgumentException("No commands provided for pipeline");
            
            await _processLock.WaitAsync();
            
            try
            {
                if (_processes.Count + commands.Count > _maxProcesses)
                {
                    throw new InvalidOperationException(
                        $"Maximum number of processes ({_maxProcesses}) would be exceeded");
                }
                
                var processes = new List<Process>();
                Process? previousProcess = null;
                StreamWriter? previousOutputStream = null;
                
                for (int i = 0; i < commands.Count; i++)
                {
                    var command = commands[i];
                    
                    if (command.Arguments.Count == 0)
                    {
                        throw new ArgumentException($"Command {i} has no arguments");
                    }
                    
                    var startInfo = new ProcessStartInfo
                    {
                        FileName = command.Arguments[0],
                        Arguments = string.Join(" ", command.Arguments.Skip(1)),
                        UseShellExecute = false,
                        CreateNoWindow = true,
                        RedirectStandardInput = i > 0, // 第一个进程不需要重定向输入
                        RedirectStandardOutput = i < commands.Count - 1, // 最后一个进程不需要重定向输出
                        RedirectStandardError = !string.IsNullOrEmpty(command.StandardError)
                    };
                    
                    // 设置工作目录
                    if (!string.IsNullOrEmpty(command.WorkingDirectory))
                    {
                        startInfo.WorkingDirectory = command.WorkingDirectory;
                    }
                    
                    // 设置环境变量
                    foreach (var kvp in command.EnvironmentVariables)
                    {
                        startInfo.EnvironmentVariables[kvp.Key] = kvp.Value;
                    }
                    
                    var process = new Process
                    {
                        StartInfo = startInfo,
                        EnableRaisingEvents = true
                    };
                    
                    // 启动进程
                    if (!process.Start())
                    {
                        throw new InvalidOperationException(
                            $"Failed to start process {i}: {command.Arguments[0]}");
                    }
                    
                    // 连接管道
                    if (previousOutputStream != null)
                    {
                        await previousOutputStream.WriteAsync(
                            await previousProcess!.StandardOutput.ReadToEndAsync());
                        previousOutputStream.Close();
                    }
                    
                    if (i < commands.Count - 1)
                    {
                        previousOutputStream = process.StandardInput;
                    }
                    
                    previousProcess = process;
                    processes.Add(process);
                    
                    // 创建进程信息
                    var processInfo = new ProcessInfo
                    {
                        Id = process.Id,
                        ParentId = System.Diagnostics.Process.GetCurrentProcess().Id,
                        Name = Path.GetFileName(command.Arguments[0]),
                        CommandLine = $"{command.Arguments[0]} {string.Join(" ", command.Arguments.Skip(1))}",
                        Status = Types.ProcessStatus.Running,
                        StartTime = DateTime.Now,
                        WorkingDirectory = startInfo.WorkingDirectory,
                        Environment = new Dictionary<string, string>(command.EnvironmentVariables)
                    };
                    
                    _processes[process.Id] = processInfo;
                }
                
                // 创建作业
                int jobId = _jobs.Count + 1;
                var jobInfo = new JobInfo
                {
                    Id = jobId,
                    ProcessIds = processes.Select(p => p.Id).ToList(),
                    Command = string.Join(" | ", commands.Select(c => c.RawCommand)),
                    Status = JobStatus.Running
                };
                
                _jobs[jobId] = jobInfo;
                
                // 设置作业ID到进程信息
                foreach (var process in processes)
                {
                    if (_processes.TryGetValue(process.Id, out ProcessInfo? info))
                    {
                        info.JobId = jobId;
                    }
                }
                
                // 监听所有进程退出
                foreach (var process in processes)
                {
                    process.Exited += (sender, e) => OnPipelineProcessExited(process, jobId);
                }
                
                return processes;
            }
            finally
            {
                _processLock.Release();
            }
        }
        
        public async Task<int> WaitForProcessAsync(int processId)
        {
            if (!_processes.TryGetValue(processId, out ProcessInfo? processInfo))
            {
                throw new ArgumentException($"Process {processId} not found");
            }
            
            try
            {
                var process = System.Diagnostics.Process.GetProcessById(processId);
                await process.WaitForExitAsync();
                return process.ExitCode;
            }
            catch (ArgumentException)
            {
                // 进程已退出
                return processInfo.ExitCode ?? -1;
            }
        }
        
        public async Task<bool> KillProcessAsync(int processId, bool force = false)
        {
            try
            {
                var process = System.Diagnostics.Process.GetProcessById(processId);
                
                if (force)
                {
                    process.Kill();
                }
                else
                {
                    // 尝试优雅关闭
                    if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                    {
                        process.CloseMainWindow();
                    }
                    else
                    {
                        process.Kill(); // Unix上通常直接kill
                    }
                    
                    // 等待进程退出
                    if (!await process.WaitForExitAsync(5000))
                    {
                        process.Kill();
                    }
                }
                
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
        
        public void KillForegroundProcess()
        {
            if (_foregroundProcess != null && !_foregroundProcess.HasExited)
            {
                try
                {
                    _foregroundProcess.Kill();
                }
                catch
                {
                    // 忽略异常
                }
            }
        }
        
        public List<ProcessInfo> GetProcesses()
        {
            return _processes.Values.ToList();
        }
        
        public List<JobInfo> GetJobs()
        {
            return _jobs.Values.ToList();
        }
        
        private void OnProcessExited(Process process, int? jobId)
        {
            if (_processes.TryGetValue(process.Id, out ProcessInfo? processInfo))
            {
                processInfo.Status = Types.ProcessStatus.Exited;
                processInfo.ExitTime = DateTime.Now;
                processInfo.ExitCode = process.ExitCode;
                
                if (jobId.HasValue)
                {
                    if (_jobs.TryGetValue(jobId.Value, out JobInfo? jobInfo))
                    {
                        jobInfo.ProcessIds.Remove(process.Id);
                        if (jobInfo.ProcessIds.Count == 0)
                        {
                            jobInfo.Status = JobStatus.Completed;
                            _jobs.TryRemove(jobId.Value, out _);
                        }
                    }
                }
                
                _processes.TryRemove(process.Id, out _);
            }
        }
        
        private void OnPipelineProcessExited(Process process, int jobId)
        {
            OnProcessExited(process, jobId);
        }
        
        private async Task MonitorProcessesAsync()
        {
            while (!_cancellationTokenSource.Token.IsCancellationRequested)
            {
                try
                {
                    await Task.Delay(1000, _cancellationTokenSource.Token);
                    
                    // 清理已退出的进程
                    var deadProcesses = new List<int>();
                    
                    foreach (var kvp in _processes)
                    {
                        var processInfo = kvp.Value;
                        
                        if (processInfo.Status == Types.ProcessStatus.Running)
                        {
                            try
                            {
                                var process = System.Diagnostics.Process.GetProcessById(kvp.Key);
                                if (process.HasExited)
                                {
                                    processInfo.Status = Types.ProcessStatus.Exited;
                                    processInfo.ExitTime = DateTime.Now;
                                    processInfo.ExitCode = process.ExitCode;
                                    deadProcesses.Add(kvp.Key);
                                }
                            }
                            catch (ArgumentException)
                            {
                                // 进程已不存在
                                processInfo.Status = Types.ProcessStatus.Terminated;
                                processInfo.ExitTime = DateTime.Now;
                                processInfo.ExitCode = -1;
                                deadProcesses.Add(kvp.Key);
                            }
                        }
                    }
                    
                    // 移除已退出的进程
                    foreach (int pid in deadProcesses)
                    {
                        _processes.TryRemove(pid, out _);
                    }
                }
                catch (OperationCanceledException)
                {
                    break;
                }
                catch (Exception)
                {
                    // 忽略监控异常
                }
            }
        }
        
        public async ValueTask DisposeAsync()
        {
            _cancellationTokenSource.Cancel();
            
            try
            {
                await _monitorTask;
            }
            catch (OperationCanceledException)
            {
                // 正常取消
            }
            
            // 终止所有子进程
            foreach (int pid in _processes.Keys)
            {
                await KillProcessAsync(pid, true);
            }
            
            _cancellationTokenSource.Dispose();
            _processLock.Dispose();
        }
    }
    
    public class JobInfo
    {
        public int Id { get; set; }
        public List<int> ProcessIds { get; set; } = new();
        public string Command { get; set; } = string.Empty;
        public JobStatus Status { get; set; }
    }
    
    public enum JobStatus
    {
        Running,
        Suspended,
        Completed,
        Terminated
    }
}

2.5 多语言脚本引擎实现

// DotNetShell/Scripting/MultiScriptEngine.cs
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using DotNetShell.Core.Types;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
using Microsoft.ClearScript;
using Microsoft.ClearScript.V8;
using IronPython.Hosting;
using IronRuby;
using NLua;
using Jint;
using PowerShell = System.Management.Automation.PowerShell;

namespace DotNetShell.Scripting
{
    public class MultiScriptEngine : IAsyncDisposable
    {
        private readonly ConcurrentDictionary<string, IScriptExecutor> _executors;
        private readonly ScriptSandbox _sandbox;
        private readonly AssemblyLoadContext _scriptAssemblyContext;
        private readonly ConcurrentDictionary<string, CompiledScript> _compiledCache;
        private readonly CancellationTokenSource _cancellationTokenSource;
        
        public MultiScriptEngine(IShellContext shell)
        {
            _executors = new ConcurrentDictionary<string, IScriptExecutor>(
                StringComparer.OrdinalIgnoreCase);
            _sandbox = new ScriptSandbox();
            _scriptAssemblyContext = new ScriptAssemblyLoadContext();
            _compiledCache = new ConcurrentDictionary<string, CompiledScript>();
            _cancellationTokenSource = new CancellationTokenSource();
            
            InitializeExecutors(shell);
        }
        
        private void InitializeExecutors(IShellContext shell)
        {
            // 注册各种脚本引擎
            RegisterExecutor("csharp", new CSharpScriptExecutor(shell));
            RegisterExecutor("vb", new VisualBasicScriptExecutor(shell));
            RegisterExecutor("powershell", new PowerShellExecutor(shell));
            RegisterExecutor("python", new PythonScriptExecutor(shell));
            RegisterExecutor("ruby", new RubyScriptExecutor(shell));
            RegisterExecutor("lua", new LuaScriptExecutor(shell));
            RegisterExecutor("javascript", new JavaScriptExecutor(shell));
            RegisterExecutor("typescript", new TypeScriptExecutor(shell));
            RegisterExecutor("perl", new PerlScriptExecutor(shell));
            RegisterExecutor("r", new RScriptExecutor(shell));
            RegisterExecutor("kotlin", new KotlinScriptExecutor(shell));
            RegisterExecutor("scala", new ScalaScriptExecutor(shell));
            RegisterExecutor("clojure", new ClojureScriptExecutor(shell));
            RegisterExecutor("wasm", new WebAssemblyExecutor(shell));
        }
        
        public void RegisterExecutor(string language, IScriptExecutor executor)
        {
            _executors[language] = executor;
        }
        
        public IScriptExecutor? GetExecutor(string language)
        {
            return _executors.TryGetValue(language, out var executor) ? executor : null;
        }
        
        public IEnumerable<string> GetSupportedLanguages()
        {
            return _executors.Keys;
        }
        
        public async Task<object?> EvaluateAsync(string language, string code, ScriptContext context)
        {
            if (!_executors.TryGetValue(language, out var executor))
            {
                throw new NotSupportedException($"Language '{language}' is not supported.");
            }
            
            // 在沙箱中执行
            return await _sandbox.ExecuteAsync(async () =>
            {
                var stopwatch = Stopwatch.StartNew();
                
                try
                {
                    // 设置资源限制
                    using var memoryMonitor = new MemoryMonitor(context.SecurityPolicy.MaxMemoryBytes);
                    using var timeoutMonitor = new TimeoutMonitor(context.SecurityPolicy.ExecutionTimeout);
                    
                    // 执行脚本
                    var result = await executor.ExecuteAsync(code, context);
                    stopwatch.Stop();
                    
                    return result;
                }
                catch (Exception ex)
                {
                    stopwatch.Stop();
                    throw new ScriptExecutionException(
                        $"Script execution failed: {ex.Message}", ex);
                }
            }, context.SecurityPolicy);
        }
        
        public async Task<object?> ExecuteFileAsync(string language, string filePath, ScriptContext context)
        {
            if (!_executors.TryGetValue(language, out var executor))
            {
                throw new NotSupportedException($"Language '{language}' is not supported.");
            }
            
            // 检查文件权限
            _sandbox.CheckFileAccess(filePath, context.SecurityPolicy);
            
            // 读取文件内容
            string code = await File.ReadAllTextAsync(filePath);
            
            // 更新上下文
            var updatedContext = context with
            {
                WorkingDirectory = Path.GetDirectoryName(filePath) ?? context.WorkingDirectory
            };
            
            return await EvaluateAsync(language, code, updatedContext);
        }
        
        public async Task<CompiledScript> CompileAsync(string language, string code)
        {
            string cacheKey = $"{language}:{code.GetHashCode():X8}";
            
            if (_compiledCache.TryGetValue(cacheKey, out var compiled))
            {
                return compiled;
            }
            
            if (!_executors.TryGetValue(language, out var executor))
            {
                throw new NotSupportedException($"Language '{language}' is not supported.");
            }
            
            compiled = await executor.CompileAsync(code);
            _compiledCache[cacheKey] = compiled;
            
            return compiled;
        }
        
        public async ValueTask DisposeAsync()
        {
            _cancellationTokenSource.Cancel();
            
            foreach (var executor in _executors.Values)
            {
                if (executor is IAsyncDisposable asyncDisposable)
                {
                    await asyncDisposable.DisposeAsync();
                }
                else if (executor is IDisposable disposable)
                {
                    disposable.Dispose();
                }
            }
            
            _executors.Clear();
            _compiledCache.Clear();
            _cancellationTokenSource.Dispose();
        }
    }
    
    // 脚本执行器接口
    public interface IScriptExecutor
    {
        string LanguageName { get; }
        string[] FileExtensions { get; }
        Task<object?> ExecuteAsync(string code, ScriptContext context);
        Task<CompiledScript> CompileAsync(string code);
    }
    
    public abstract class CompiledScript
    {
        public abstract Task<object?> ExecuteAsync(ScriptContext context);
    }
    
    // C# 脚本执行器 (基于Roslyn)
    public class CSharpScriptExecutor : IScriptExecutor, IAsyncDisposable
    {
        private readonly IShellContext _shell;
        private readonly ScriptOptions _scriptOptions;
        private readonly ConcurrentDictionary<string, ScriptRunner<object>> _scriptCache;
        
        public string LanguageName => "csharp";
        public string[] FileExtensions => new[] { ".cs", ".csx" };
        
        public CSharpScriptExecutor(IShellContext shell)
        {
            _shell = shell;
            _scriptCache = new ConcurrentDictionary<string, ScriptRunner<object>>();
            
            // 配置脚本选项
            _scriptOptions = ScriptOptions.Default
                .WithReferences(
                    typeof(object).Assembly,
                    typeof(Console).Assembly,
                    typeof(System.Linq.Enumerable).Assembly,
                    typeof(System.Dynamic.ExpandoObject).Assembly,
                    typeof(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo).Assembly)
                .WithImports(
                    "System",
                    "System.Collections.Generic",
                    "System.Linq",
                    "System.Text",
                    "System.IO",
                    "System.Threading.Tasks")
                .WithEmitDebugInformation(true)
                .WithFileEncoding(Encoding.UTF8);
        }
        
        public async Task<object?> ExecuteAsync(string code, ScriptContext context)
        {
            string cacheKey = $"csharp:{code.GetHashCode():X8}";
            
            var scriptRunner = _scriptCache.GetOrAdd(cacheKey, _ =>
            {
                var script = CSharpScript.Create<object>(
                    code,
                    _scriptOptions,
                    typeof(ScriptGlobals));
                
                return script.CreateDelegate();
            });
            
            var globals = new ScriptGlobals
            {
                Shell = _shell,
                Context = context,
                Env = new Dictionary<string, string>(context.Environment),
                Args = context.Arguments.ToArray(),
                WorkingDirectory = context.WorkingDirectory
            };
            
            ScriptState<object> state = await scriptRunner(globals);
            return state.ReturnValue;
        }
        
        public async Task<CompiledScript> CompileAsync(string code)
        {
            var script = CSharpScript.Create<object>(
                code,
                _scriptOptions,
                typeof(ScriptGlobals));
            
            var compiled = await script.CompileAsync();
            
            return new CSharpCompiledScript(script);
        }
        
        public async ValueTask DisposeAsync()
        {
            _scriptCache.Clear();
            await Task.CompletedTask;
        }
        
        public class ScriptGlobals
        {
            public IShellContext? Shell { get; set; }
            public ScriptContext? Context { get; set; }
            public Dictionary<string, string>? Env { get; set; }
            public string[]? Args { get; set; }
            public string? WorkingDirectory { get; set; }
            
            public void Print(object? value) => Console.WriteLine(value);
            public void Echo(object? value) => Console.WriteLine(value);
        }
        
        private class CSharpCompiledScript : CompiledScript
        {
            private readonly Script<object> _script;
            
            public CSharpCompiledScript(Script<object> script)
            {
                _script = script;
            }
            
            public override async Task<object?> ExecuteAsync(ScriptContext context)
            {
                var globals = new ScriptGlobals
                {
                    Context = context,
                    Env = new Dictionary<string, string>(context.Environment),
                    Args = context.Arguments.ToArray(),
                    WorkingDirectory = context.WorkingDirectory
                };
                
                ScriptState<object> state = await _script.RunAsync(globals);
                return state.ReturnValue;
            }
        }
    }
    
    // JavaScript 执行器 (基于ClearScript/V8)
    public class JavaScriptExecutor : IScriptExecutor, IDisposable
    {
        private readonly IShellContext _shell;
        private readonly V8ScriptEngine _engine;
        private readonly ConcurrentDictionary<string, V8Script> _scriptCache;
        
        public string LanguageName => "javascript";
        public string[] FileExtensions => new[] { ".js", ".es", ".mjs" };
        
        public JavaScriptExecutor(IShellContext shell)
        {
            _shell = shell;
            _engine = new V8ScriptEngine(V8ScriptEngineFlags.EnableDebugging);
            _scriptCache = new ConcurrentDictionary<string, V8Script>();
            
            InitializeEngine();
        }
        
        private void InitializeEngine()
        {
            // 注入全局对象
            _engine.AddHostObject("shell", HostItemFlags.GlobalMembers, _shell);
            _engine.AddHostObject("console", HostItemFlags.GlobalMembers, new ConsoleObject());
            _engine.AddHostObject("process", HostItemFlags.GlobalMembers, new ProcessObject());
            
            // 注入常用函数
            _engine.AddHostObject("print", HostItemFlags.GlobalMembers, 
                new Action<object?>(value => Console.WriteLine(value)));
            
            _engine.AddHostObject("require", HostItemFlags.GlobalMembers,
                new Func<string, object>(RequireModule));
            
            // 设置超时
            _engine.ScriptTimeout = 30000; // 30秒
        }
        
        public async Task<object?> ExecuteAsync(string code, ScriptContext context)
        {
            string cacheKey = $"js:{code.GetHashCode():X8}";
            
            var compiledScript = _scriptCache.GetOrAdd(cacheKey, _ =>
            {
                return _engine.Compile(code);
            });
            
            // 设置上下文变量
            _engine.Script.__context = context;
            _engine.Script.__env = context.Environment;
            _engine.Script.__args = context.Arguments.ToArray();
            _engine.Script.__dirname = context.WorkingDirectory;
            
            return await Task.Run(() => _engine.Evaluate(compiledScript));
        }
        
        public Task<CompiledScript> CompileAsync(string code)
        {
            var compiled = _engine.Compile(code);
            
            return Task.FromResult<CompiledScript>(
                new JavaScriptCompiledScript(compiled, _engine));
        }
        
        private object RequireModule(string moduleName)
        {
            // 简化版模块加载
            if (moduleName == "fs")
            {
                return new FileSystemModule();
            }
            else if (moduleName == "path")
            {
                return new PathModule();
            }
            
            throw new ScriptEngineException($"Module '{moduleName}' not found");
        }
        
        public void Dispose()
        {
            _scriptCache.Clear();
            _engine.Dispose();
        }
        
        private class ConsoleObject
        {
            public void log(params object?[] args)
            {
                Console.WriteLine(string.Join(" ", args.Select(a => a?.ToString())));
            }
            
            public void error(params object?[] args)
            {
                var oldColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Red;
                Console.Error.WriteLine(string.Join(" ", args.Select(a => a?.ToString())));
                Console.ForegroundColor = oldColor;
            }
            
            public void warn(params object?[] args)
            {
                var oldColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine(string.Join(" ", args.Select(a => a?.ToString())));
                Console.ForegroundColor = oldColor;
            }
        }
        
        private class ProcessObject
        {
            public string cwd() => Directory.GetCurrentDirectory();
            public void chdir(string path) => Directory.SetCurrentDirectory(path);
            public Dictionary<string, string> env => 
                Environment.GetEnvironmentVariables()
                    .Cast<System.Collections.DictionaryEntry>()
                    .ToDictionary(e => e.Key.ToString()!, e => e.Value?.ToString() ?? "");
        }
        
        private class JavaScriptCompiledScript : CompiledScript
        {
            private readonly V8Script _script;
            private readonly V8ScriptEngine _engine;
            
            public JavaScriptCompiledScript(V8Script script, V8ScriptEngine engine)
            {
                _script = script;
                _engine = engine;
            }
            
            public override Task<object?> ExecuteAsync(ScriptContext context)
            {
                return Task.Run(() =>
                {
                    // 设置上下文
                    _engine.Script.__context = context;
                    _engine.Script.__env = context.Environment;
                    _engine.Script.__args = context.Arguments.ToArray();
                    
                    return _engine.Evaluate(_script);
                });
            }
        }
    }
    
    // Python 执行器 (基于IronPython)
    public class PythonScriptExecutor : IScriptExecutor, IDisposable
    {
        private readonly IShellContext _shell;
        private readonly Microsoft.Scripting.Hosting.ScriptEngine _engine;
        private readonly Microsoft.Scripting.Hosting.ScriptScope _scope;
        
        public string LanguageName => "python";
        public string[] FileExtensions => new[] { ".py", ".pyw" };
        
        public PythonScriptExecutor(IShellContext shell)
        {
            _shell = shell;
            _engine = Python.CreateEngine();
            _scope = _engine.CreateScope();
            
            InitializeEngine();
        }
        
        private void InitializeEngine()
        {
            // 设置搜索路径
            var paths = _engine.GetSearchPaths();
            paths.Add(Path.Combine(Environment.CurrentDirectory, "python"));
            paths.Add(Path.Combine(Environment.GetFolderPath(
                Environment.SpecialFolder.UserProfile), ".python"));
            _engine.SetSearchPaths(paths);
            
            // 注入全局变量
            _scope.SetVariable("shell", _shell);
            _scope.SetVariable("print", new Action<object?>(Console.WriteLine));
            
            // 注入内置模块
            _scope.Engine.Execute(@"
import sys
import clr
clr.AddReference('System')
from System import *
", _scope);
        }
        
        public async Task<object?> ExecuteAsync(string code, ScriptContext context)
        {
            return await Task.Run(() =>
            {
                try
                {
                    // 设置上下文
                    _scope.SetVariable("__context__", context);
                    _scope.SetVariable("__env__", context.Environment);
                    _scope.SetVariable("__args__", context.Arguments);
                    _scope.SetVariable("__dirname__", context.WorkingDirectory);
                    
                    var scriptSource = _engine.CreateScriptSourceFromString(
                        code, Microsoft.Scripting.SourceCodeKind.Statements);
                    
                    return scriptSource.Execute(_scope);
                }
                catch (Microsoft.Scripting.SyntaxErrorException ex)
                {
                    throw new ScriptExecutionException($"Python syntax error: {ex.Message}", ex);
                }
                catch (Exception ex)
                {
                    throw new ScriptExecutionException($"Python execution error: {ex.Message}", ex);
                }
            });
        }
        
        public Task<CompiledScript> CompileAsync(string code)
        {
            var scriptSource = _engine.CreateScriptSourceFromString(
                code, Microsoft.Scripting.SourceCodeKind.Statements);
            
            var compiledCode = scriptSource.Compile();
            
            return Task.FromResult<CompiledScript>(
                new PythonCompiledScript(compiledCode, _scope));
        }
        
        public void Dispose()
        {
            // IronPython引擎没有明确的Dispose方法
        }
        
        private class PythonCompiledScript : CompiledScript
        {
            private readonly Microsoft.Scripting.Hosting.CompiledCode _compiledCode;
            private readonly Microsoft.Scripting.Hosting.ScriptScope _scope;
            
            public PythonCompiledScript(
                Microsoft.Scripting.Hosting.CompiledCode compiledCode,
                Microsoft.Scripting.Hosting.ScriptScope scope)
            {
                _compiledCode = compiledCode;
                _scope = scope;
            }
            
            public override Task<object?> ExecuteAsync(ScriptContext context)
            {
                return Task.Run(() =>
                {
                    _scope.SetVariable("__context__", context);
                    _scope.SetVariable("__env__", context.Environment);
                    
                    return _compiledCode.Execute(_scope);
                });
            }
        }
    }
    
    // PowerShell 执行器
    public class PowerShellExecutor : IScriptExecutor, IDisposable
    {
        private readonly IShellContext _shell;
        
        public string LanguageName => "powershell";
        public string[] FileExtensions => new[] { ".ps1", ".psm1", ".psd1" };
        
        public PowerShellExecutor(IShellContext shell)
        {
            _shell = shell;
        }
        
        public async Task<object?> ExecuteAsync(string code, ScriptContext context)
        {
            return await Task.Run(() =>
            {
                using var powerShell = PowerShell.Create();
                
                // 设置执行策略
                powerShell.AddScript("Set-ExecutionPolicy -Scope Process -ExecutionPolicy RemoteSigned");
                powerShell.Invoke();
                powerShell.Commands.Clear();
                
                // 设置变量
                foreach (var kvp in context.Environment)
                {
                    powerShell.Runspace.SessionStateProxy.SetVariable(kvp.Key, kvp.Value);
                }
                
                powerShell.Runspace.SessionStateProxy.SetVariable("Shell", _shell);
                powerShell.Runspace.SessionStateProxy.SetVariable("Context", context);
                powerShell.Runspace.SessionStateProxy.Path.SetLocation(context.WorkingDirectory);
                
                // 执行脚本
                powerShell.AddScript(code);
                
                var results = powerShell.Invoke();
                
                if (powerShell.HadErrors)
                {
                    var errors = string.Join("\n", 
                        powerShell.Streams.Error.Select(e => e.ToString()));
                    throw new ScriptExecutionException($"PowerShell errors:\n{errors}");
                }
                
                // 返回最后一个结果
                return results.LastOrDefault()?.BaseObject;
            });
        }
        
        public Task<CompiledScript> CompileAsync(string code)
        {
            // PowerShell通常是解释执行的,这里返回一个包装器
            return Task.FromResult<CompiledScript>(new PowerShellCompiledScript(code));
        }
        
        public void Dispose()
        {
            // PowerShell对象在using语句中已清理
        }
        
        private class PowerShellCompiledScript : CompiledScript
        {
            private readonly string _code;
            
            public PowerShellCompiledScript(string code)
            {
                _code = code;
            }
            
            public override Task<object?> ExecuteAsync(ScriptContext context)
            {
                using var powerShell = PowerShell.Create();
                
                foreach (var kvp in context.Environment)
                {
                    powerShell.Runspace.SessionStateProxy.SetVariable(kvp.Key, kvp.Value);
                }
                
                powerShell.Runspace.SessionStateProxy.Path.SetLocation(context.WorkingDirectory);
                powerShell.AddScript(_code);
                
                var results = powerShell.Invoke();
                return Task.FromResult(results.LastOrDefault()?.BaseObject);
            }
        }
    }
    
    // Lua 执行器 (基于NLua)
    public class LuaScriptExecutor : IScriptExecutor, IDisposable
    {
        private readonly IShellContext _shell;
        private readonly Lua _lua;
        
        public string LanguageName => "lua";
        public string[] FileExtensions => new[] { ".lua" };
        
        public LuaScriptExecutor(IShellContext shell)
        {
            _shell = shell;
            _lua = new Lua();
            
            InitializeEngine();
        }
        
        private void InitializeEngine()
        {
            // 注册全局函数
            _lua.RegisterFunction("print", this, GetType().GetMethod(nameof(LuaPrint)));
            _lua.RegisterFunction("shell", _shell, _shell.GetType().GetMethod("WriteLine"));
            
            // 设置标准库
            _lua.DoString(@"
                math = require('math')
                string = require('string')
                table = require('table')
                io = require('io')
                os = require('os')
            ");
        }
        
        public static void LuaPrint(params object[] args)
        {
            Console.WriteLine(string.Join("\t", args));
        }
        
        public async Task<object?> ExecuteAsync(string code, ScriptContext context)
        {
            return await Task.Run(() =>
            {
                try
                {
                    // 设置全局变量
                    _lua["_ENV"] = context.Environment;
                    _lua["_ARGS"] = context.Arguments.ToArray();
                    _lua["_CWD"] = context.WorkingDirectory;
                    
                    return _lua.DoString(code)[0];
                }
                catch (NLua.Exceptions.LuaException ex)
                {
                    throw new ScriptExecutionException($"Lua error: {ex.Message}", ex);
                }
            });
        }
        
        public Task<CompiledScript> CompileAsync(string code)
        {
            // Lua通常是解释执行的
            return Task.FromResult<CompiledScript>(new LuaCompiledScript(code, _lua));
        }
        
        public void Dispose()
        {
            _lua?.Dispose();
        }
        
        private class LuaCompiledScript : CompiledScript
        {
            private readonly string _code;
            private readonly Lua _lua;
            
            public LuaCompiledScript(string code, Lua lua)
            {
                _code = code;
                _lua = lua;
            }
            
            public override Task<object?> ExecuteAsync(ScriptContext context)
            {
                return Task.Run(() =>
                {
                    _lua["_ENV"] = context.Environment;
                    _lua["_ARGS"] = context.Arguments.ToArray();
                    
                    return _lua.DoString(_code)[0];
                });
            }
        }
    }
    
    // 更多脚本引擎实现...
    
    // 异常类
    public class ScriptExecutionException : Exception
    {
        public ScriptExecutionException(string message, Exception? innerException = null)
            : base(message, innerException)
        {
        }
    }
    
    public class ScriptEngineException : Exception
    {
        public ScriptEngineException(string message, Exception? innerException = null)
            : base(message, innerException)
        {
        }
    }
    
    // 沙箱和安全相关类
    public class ScriptSandbox
    {
        public async Task<T> ExecuteAsync<T>(Func<Task<T>> action, ScriptContext.SecurityPolicy policy)
        {
            // 实现资源限制和权限检查
            using var cts = new CancellationTokenSource(policy.ExecutionTimeout);
            
            try
            {
                return await Task.Run(async () =>
                {
                    using var memoryLimiter = new MemoryLimiter(policy.MaxMemoryBytes);
                    
                    return await action();
                }, cts.Token);
            }
            catch (OperationCanceledException) when (cts.Token.IsCancellationRequested)
            {
                throw new TimeoutException($"Script execution timeout after {policy.ExecutionTimeout}");
            }
        }
        
        public void CheckFileAccess(string filePath, ScriptContext.SecurityPolicy policy)
        {
            if (!policy.AllowFileSystemAccess)
            {
                throw new SecurityException("File system access is not allowed");
            }
            
            // 检查路径是否在允许的列表中
            if (policy.AllowedPaths.Count > 0)
            {
                bool allowed = policy.AllowedPaths.Any(path =>
                    filePath.StartsWith(path, StringComparison.OrdinalIgnoreCase));
                
                if (!allowed)
                {
                    throw new SecurityException($"Access to '{filePath}' is not allowed");
                }
            }
        }
    }
    
    public class MemoryLimiter : IDisposable
    {
        private readonly long _maxBytes;
        private readonly long _initialMemory;
        
        public MemoryLimiter(long maxBytes)
        {
            _maxBytes = maxBytes;
            _initialMemory = GC.GetTotalMemory(false);
        }
        
        public void Check()
        {
            long currentMemory = GC.GetTotalMemory(false);
            long usedMemory = currentMemory - _initialMemory;
            
            if (usedMemory > _maxBytes)
            {
                throw new OutOfMemoryException(
                    $"Script exceeded memory limit: {usedMemory:N0} > {_maxBytes:N0} bytes");
            }
        }
        
        public void Dispose()
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
    }
    
    public class ScriptAssemblyLoadContext : AssemblyLoadContext
    {
        public ScriptAssemblyLoadContext() : base(isCollectible: true)
        {
        }
        
        protected override Assembly? Load(AssemblyName assemblyName)
        {
            // 允许加载系统程序集
            if (assemblyName.Name?.StartsWith("System.") == true ||
                assemblyName.Name?.StartsWith("Microsoft.") == true)
            {
                return Assembly.Load(assemblyName);
            }
            
            // 对于其他程序集,可以实施安全策略
            return null;
        }
    }
}

三、设计工具与流程

3.1 .NET企业级设计模式

部署

打包: NuGet包, Docker镜像

部署: Kubernetes, Docker Swarm, Azure

监控: Application Insights, Prometheus

日志: Serilog, ELK Stack

测试

单元测试: xUnit, NUnit, MSTest

集成测试: TestServer, WebApplicationFactory

性能测试: Benchmark.NET, k6

安全测试: OWASP, Security Code Scan

实现

开发工具: Visual Studio 2022, VS Code

构建工具: .NET CLI, MSBuild, Cake

依赖管理: NuGet, Paket

代码质量: Roslyn分析器, SonarQube

详细设计

设计模式: 工厂, 策略, 观察者, 装饰器

API设计: REST API, gRPC, SignalR

数据设计: 实体框架, 缓存策略

安全设计: 认证, 授权, 审计

架构设计

分层架构: UI层/业务层/数据层

微服务架构: 可独立部署的组件

接口设计: 抽象与依赖注入

并发设计: async/await, 通道, 数据流

需求分析

功能需求: Shell, Process, Multi-language Scripting

性能需求: 异步, 并发, 低延迟

安全需求: 沙箱, 权限控制, 代码签名

企业需求: 日志, 监控, 配置管理

3.2 C#/.NET特性应用

  1. 异步编程模式
public async Task<int> ExecuteCommandAsync(string command)
{
    // 使用async/await进行异步操作
    var parsed = await _parser.ParseAsync(command);
    
    // 使用WhenAll并行执行多个任务
    var tasks = parsed.Commands.Select(cmd => ExecuteSingleCommandAsync(cmd));
    var results = await Task.WhenAll(tasks);
    
    return results.LastOrDefault();
}

// 使用ValueTask优化性能
public async ValueTask<object?> EvaluateScriptAsync(string language, string code)
{
    if (_compiledCache.TryGetValue(code, out var compiled))
    {
        return await compiled.ExecuteAsync();
    }
    
    // 编译并缓存
    var newCompiled = await CompileAsync(language, code);
    _compiledCache[code] = newCompiled;
    
    return await newCompiled.ExecuteAsync();
}
  1. 记录类型和模式匹配
// 使用记录类型表示不可变数据
public record CommandResult(
    int ExitCode,
    string Output,
    string Error,
    TimeSpan ExecutionTime,
    DateTime Timestamp)
{
    public bool IsSuccess => ExitCode == 0;
}

// 使用模式匹配进行条件处理
public string FormatResult(CommandResult result) => result switch
{
    { IsSuccess: true, Output: var output } when !string.IsNullOrEmpty(output) =>
        $"Success: {output}",
    { IsSuccess: true } => "Command completed successfully",
    { Error: var error } when !string.IsNullOrEmpty(error) =>
        $"Error: {error}",
    _ => $"Failed with exit code {result.ExitCode}"
};
  1. 依赖注入和配置
public static IServiceCollection AddDotNetShell(this IServiceCollection services, 
    IConfiguration configuration)
{
    // 注册配置
    services.Configure<ShellConfiguration>(configuration.GetSection("Shell"));
    
    // 注册核心服务
    services.AddSingleton<IShellContext, DotNetShell>();
    services.AddSingleton<ProcessManager>();
    services.AddSingleton<MultiScriptEngine>();
    
    // 注册脚本引擎
    services.AddSingleton<IScriptExecutor, CSharpScriptExecutor>();
    services.AddSingleton<IScriptExecutor, JavaScriptExecutor>();
    services.AddSingleton<IScriptExecutor, PowerShellExecutor>();
    // 更多引擎...
    
    // 注册内置命令
    services.Scan(scan => scan
        .FromAssemblyOf<IBuiltinCommand>()
        .AddClasses(classes => classes.AssignableTo<IBuiltinCommand>())
        .As<IBuiltinCommand>()
        .WithSingletonLifetime());
    
    return services;
}
  1. 源生成器优化
// 使用源生成器自动生成命令补全数据
[AutoCompleteSourceGenerator]
public partial class CommandCompleter
{
    [AutoComplete("cd")]
    public static IEnumerable<string> GetDirectoryCompletions(string partial)
    {
        return Directory.EnumerateDirectories(".", $"{partial}*")
            .Select(Path.GetFileName)
            .Where(name => name != null)!;
    }
    
    [AutoComplete("git")]
    public static IEnumerable<string> GetGitCompletions(string partial)
    {
        return new[] { "clone", "pull", "push", "commit", "status" }
            .Where(cmd => cmd.StartsWith(partial));
    }
}

四、测试与验证

4.1 单元测试示例

// DotNetShell.Tests/ShellTests.cs
using Xunit;
using Moq;
using DotNetShell.Shell;
using DotNetShell.Core.Types;

namespace DotNetShell.Tests
{
    public class ShellTests : IAsyncLifetime
    {
        private DotNetShell _shell;
        private Mock<ILogger<DotNetShell>> _loggerMock;
        
        public async Task InitializeAsync()
        {
            _loggerMock = new Mock<ILogger<DotNetShell>>();
            var config = new ShellConfiguration
            {
                Prompt = "test> ",
                EnableColors = false,
                EnableCompletion = false
            };
            
            _shell = new DotNetShell(config, _loggerMock.Object);
        }
        
        public Task DisposeAsync()
        {
            return _shell.DisposeAsync().AsTask();
        }
        
        [Fact]
        public async Task TestChangeDirectory()
        {
            // 测试cd命令
            string tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
            Directory.CreateDirectory(tempDir);
            
            try
            {
                int exitCode = await _shell.ExecuteCommandAsync($"cd {tempDir}");
                Assert.Equal(0, exitCode);
                Assert.Equal(tempDir, _shell.CurrentDirectory);
            }
            finally
            {
                Directory.Delete(tempDir);
            }
        }
        
        [Fact]
        public async Task TestEnvironmentVariables()
        {
            // 测试环境变量设置
            int exitCode = await _shell.ExecuteCommandAsync("set TEST_VAR=test_value");
            Assert.Equal(0, exitCode);
            
            string value = _shell.EnvironmentVariables["TEST_VAR"];
            Assert.Equal("test_value", value);
        }
        
        [Fact]
        public async Task TestScriptExecution()
        {
            // 测试C#脚本执行
            int exitCode = await _shell.ExecuteCommandAsync("cs> 1 + 2 * 3");
            Assert.Equal(0, exitCode);
        }
        
        [Fact]
        public async Task TestPipelineExecution()
        {
            // 创建测试文件
            string testFile = Path.GetTempFileName();
            await File.WriteAllLinesAsync(testFile, new[] { "line1", "line2", "line3" });
            
            try
            {
                // 测试管道命令
                int exitCode = await _shell.ExecuteCommandAsync(
                    $"type {testFile} | findstr line2");
                
                Assert.Equal(0, exitCode);
            }
            finally
            {
                File.Delete(testFile);
            }
        }
        
        [Fact]
        public async Task TestTimeout()
        {
            // 测试脚本超时
            var config = new ShellConfiguration
            {
                ExecutionTimeout = TimeSpan.FromSeconds(1)
            };
            
            using var shell = new DotNetShell(config);
            
            // 执行一个长时间运行的脚本
            await Assert.ThrowsAsync<TimeoutException>(() =>
                shell.ExecuteCommandAsync("cs> while(true) { }"));
        }
    }
}

// DotNetShell.Tests/ScriptingTests.cs
namespace DotNetShell.Tests.Scripting
{
    public class ScriptingTests
    {
        [Fact]
        public async Task TestCSharpScripting()
        {
            var shellMock = new Mock<IShellContext>();
            var executor = new CSharpScriptExecutor(shellMock.Object);
            
            object? result = await executor.ExecuteAsync("1 + 2 * 3", new ScriptContext());
            
            Assert.Equal(7, result);
        }
        
        [Fact]
        public async Task TestJavaScriptScripting()
        {
            var shellMock = new Mock<IShellContext>();
            using var executor = new JavaScriptExecutor(shellMock.Object);
            
            object? result = await executor.ExecuteAsync("3 * 4 + 5", new ScriptContext());
            
            Assert.Equal(17.0, Convert.ToDouble(result));
        }
        
        [Theory]
        [InlineData("csharp", "Console.WriteLine(\"Hello\");", null)]
        [InlineData("javascript", "console.log('Hello');", null)]
        [InlineData("python", "print('Hello')", null)]
        [InlineData("powershell", "Write-Host 'Hello'", null)]
        public async Task TestMultiLanguageSupport(string language, string code, object? expected)
        {
            var shellMock = new Mock<IShellContext>();
            var engine = new MultiScriptEngine(shellMock.Object);
            
            try
            {
                object? result = await engine.EvaluateAsync(language, code, new ScriptContext());
                
                if (expected != null)
                {
                    Assert.Equal(expected, result);
                }
            }
            catch (NotSupportedException) when (language == "python" || language == "powershell")
            {
                // 某些引擎可能需要额外的依赖
                Assert.True(true); // 跳过测试
            }
        }
    }
}

4.2 性能基准测试

// DotNetShell.Benchmarks/ProcessBenchmarks.cs
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using DotNetShell.Process;
using DotNetShell.Core.Types;

namespace DotNetShell.Benchmarks
{
    [MemoryDiagnoser]
    [ThreadingDiagnoser]
    public class ProcessBenchmarks : IAsyncDisposable
    {
        private ProcessManager _processManager;
        private ParsedCommand _simpleCommand;
        
        [GlobalSetup]
        public void Setup()
        {
            _processManager = new ProcessManager(100);
            _simpleCommand = new ParsedCommand
            {
                Arguments = new List<string> { "cmd.exe", "/c", "echo benchmark" },
                RunInBackground = false
            };
        }
        
        [Benchmark]
        public async Task ProcessCreation()
        {
            using var process = await _processManager.CreateProcessAsync(_simpleCommand);
            await _processManager.WaitForProcessAsync(process.Id);
        }
        
        [Benchmark]
        public async Task PipelineCreation()
        {
            var commands = new List<ParsedCommand>
            {
                new() { Arguments = new List<string> { "cmd.exe", "/c", "echo test1\ntest2\ntest3" } },
                new() { Arguments = new List<string> { "findstr", "test2" } }
            };
            
            var processes = await _processManager.CreatePipelineAsync(commands);
            
            foreach (var process in processes)
            {
                await _processManager.WaitForProcessAsync(process.Id);
            }
        }
        
        [Benchmark]
        public async Task ScriptEvaluation()
        {
            var shellMock = new Mock<IShellContext>();
            var executor = new CSharpScriptExecutor(shellMock.Object);
            
            string code = @"
                int sum = 0;
                for (int i = 0; i < 1000; i++) {
                    sum += i;
                }
                return sum;
            ";
            
            await executor.ExecuteAsync(code, new ScriptContext());
        }
        
        public async ValueTask DisposeAsync()
        {
            await _processManager.DisposeAsync();
        }
    }
    
    public class Program
    {
        public static void Main(string[] args)
        {
            var summary = BenchmarkRunner.Run<ProcessBenchmarks>();
            Console.WriteLine(summary);
        }
    }
}

五、部署与使用

5.1 构建与安装

# 克隆项目
git clone https://github.com/yourname/dotnetshell.git
cd dotnetshell

# 恢复NuGet包
dotnet restore

# 构建项目
dotnet build --configuration Release

# 运行测试
dotnet test

# 发布独立应用
dotnet publish -c Release -r win-x64 --self-contained true
dotnet publish -c Release -r linux-x64 --self-contained true
dotnet publish -c Release -r osx-x64 --self-contained true

# 安装为全局工具
dotnet tool install -g DotNetShell

# 使用Docker构建
docker build -t dotnetshell .
docker run -it --rm dotnetshell

# 使用Kubernetes部署
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml

5.2 配置文件

// appsettings.json
{
  "Shell": {
    "Prompt": "λ> ",
    "HistoryFilePath": "~/.dnsh_history",
    "HistorySize": 5000,
    "EnableColors": true,
    "EnableCompletion": true,
    "MaxProcesses": 1000,
    "ExecutionTimeout": "00:00:30",
    "InitScriptPath": "~/.dnshrc",
    "DefaultScriptLanguage": "csharp"
  },
  "Environment": {
    "EDITOR": "code",
    "PAGER": "less",
    "LC_ALL": "en_US.UTF-8",
    "DOTNET_CLI_TELEMETRY_OPTOUT": "1"
  },
  "Aliases": {
    "ll": "dir /w",
    "gs": "git status",
    "gp": "git pull",
    "gcm": "git commit -m"
  },
  "Scripting": {
    "Languages": {
      "csharp": {
        "Enabled": true,
        "AllowReflection": false,
        "MaxMemoryBytes": 104857600
      },
      "powershell": {
        "Enabled": true,
        "ExecutionPolicy": "RemoteSigned"
      },
      "python": {
        "Enabled": true,
        "SearchPaths": [
          "./python",
          "~/.python"
        ]
      },
      "javascript": {
        "Enabled": true,
        "Timeout": 30000
      }
    },
    "Security": {
      "DefaultPolicy": {
        "AllowFileSystemAccess": true,
        "AllowNetworkAccess": false,
        "AllowNativeCode": false,
        "MaxMemoryBytes": 104857600,
        "ExecutionTimeout": "00:00:30"
      },
      "RestrictedPolicy": {
        "AllowFileSystemAccess": false,
        "AllowNetworkAccess": false,
        "MaxMemoryBytes": 10485760,
        "ExecutionTimeout": "00:00:05"
      }
    }
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "System": "Warning"
    },
    "File": {
      "Path": "~/.dnsh/logs/dnsh.log",
      "MaxSize": 10485760,
      "MaxFiles": 10
    }
  },
  "Remote": {
    "Ssh": {
      "Enabled": false,
      "Port": 2222,
      "AuthorizedKeysFile": "~/.ssh/authorized_keys"
    },
    "Web": {
      "Enabled": false,
      "Url": "http://localhost:8080",
      "EnableWebSocket": true
    }
  }
}

六、总结与展望

6.1 系统特点

  1. 企业级.NET实现
    · 完全的异步支持
    · 强大的类型系统
    · 完善的异常处理
    · 丰富的生态系统
  2. 多语言脚本支持
    · C#/VB.NET (Roslyn)
    · PowerShell
    · Python (IronPython)
    · JavaScript/TypeScript
    · Lua, Ruby, R等
    · WebAssembly
  3. 安全与隔离
    · 代码沙箱
    · 资源限制
    · 权限控制
    · 程序集隔离
  4. 现代化特性
    · 异步流处理
    · 模式匹配
    · 记录类型
    · 源生成器

6.2 .NET实现优势

特性 优势
跨平台 Windows/Linux/macOS全支持
高性能 AOT编译, 值类型, 内存池
安全性 托管代码, 内存安全, 类型安全
工具链 Visual Studio, JetBrains Rider
生态系统 NuGet包管理器, 丰富的库
云原生 Docker, Kubernetes, 微服务支持

6.3 扩展方向

  1. 更多脚本语言
    · F#脚本支持
    · Go (通过Go.NET)
    · Rust (通过Rust.NET)
    · SQL (Transact-SQL)
  2. 云集成
    · Azure Functions集成
    · AWS Lambda支持
    · 容器化部署
    · Serverless架构
  3. AI增强
    · 智能命令补全
    · 自然语言命令
    · 代码生成
    · 自动文档
  4. 协作功能
    · 实时协同编辑
    · 终端共享
    · 会话录制
    · 审计跟踪

这个C# .NET实现的Shell系统充分利用了.NET生态系统的强大能力,构建了一个功能完整、安全可靠、性能优异的命令行环境。通过现代化的语言特性和企业级的设计模式,系统具有良好的可维护性、可扩展性和高性能,适合各种规模的企业应用场景。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐