找回密码
 立即注册
首页 业界区 安全 dotnet 在新进程执行某段委托的方法

dotnet 在新进程执行某段委托的方法

卓卞恻 4 天前
大概的 API 设计如下:
  1. RemoteExecutor.Invoke(() =>
  2. {
  3.     // 在这里编写在新进程执行的委托代码
  4. });
复制代码
要在 Main 函数里面调用 RemoteExecutor.TryHandle 处理命令行,因为新进程里面执行的逻辑本身就需要 Main 函数参与。标准预期写法如下
  1. if (RemoteExecutor.TryHandle(args))
  2. {
  3.     return;
  4. }
复制代码
核心实现原理就是反射获取委托所在的方法,通过方法反射调用而已
大家都知道,在 C# dotnet 里面,委托是会被生成为独立类型的。利用此原理,获取委托所在的程序集、类型、方法名,将其作为命令行参数传递过去到新进程。在新进程里面,读取传入的命令行参数,了解到当前应该反射执行哪个方法,从而执行到委托的逻辑
这个过程里面,可以看到是给新进程去执行的,意味着过程中禁止任何捕获字段,任何的委托捕获对象都不能给传递到新进程里面
以下是示例调用的全部代码:
  1. using System.Globalization;using RemoteExecutors;if (RemoteExecutor.TryHandle(args))
  2. {
  3.     return;
  4. }RemoteExecutor.Invoke(() =>{    // 写个文件测试一下    var file = Path.Join(AppContext.BaseDirectory, "1.txt");    File.WriteAllText(file, DateTime.Now.ToString(CultureInfo.InvariantCulture));});Console.WriteLine("Hello, World!");
复制代码
可以看到在这个写法里面,可以很方便将一个委托放在另一个进程去执行
本文提供的 RemoteExecutor 类的实现也非常简单,大家看一下代码就明白了原理
  1. public static class RemoteExecutor
  2. {
  3.     public static void Invoke(Action action)
  4.     {
  5.         var method = action.Method;
  6.         Type? type = method.DeclaringType;
  7.         if (type is null)
  8.         {
  9.             throw new ArgumentException();
  10.         }
  11.         TypeInfo typeInfo = IntrospectionExtensions.GetTypeInfo(type);
  12.         var methodName = method.Name;
  13.         var className = typeInfo.FullName!;
  14.         var assemblyFullName = typeInfo.Assembly.FullName!;
  15.         string[] commandLineArgs =
  16.             [
  17.                 RemoteExecutorOption.CommandName,
  18.                 "--AssemblyName", assemblyFullName,
  19.                 "--ClassName", className,
  20.                 "--MethodName", methodName,
  21.             ];
  22.         var processPath = Environment.ProcessPath;
  23.         if (processPath is null)
  24.         {
  25.             throw new InvalidOperationException();
  26.         }
  27.         var process = Process.Start(processPath,commandLineArgs);
  28.         process.WaitForExit();
  29.     }
  30.     public static bool TryHandle(string[] commandLineArgs)
  31.     {
  32.         var index = commandLineArgs.IndexOf(RemoteExecutorOption.CommandName);
  33.         if (index == -1)
  34.         {
  35.             return false;
  36.         }
  37.         var optionCommandLineArgs = commandLineArgs.Skip(index+1).ToList();
  38.         var result = CommandLine.Parse(optionCommandLineArgs)
  39.             .AddHandler<RemoteExecutorOption>(option =>
  40.             {
  41.                 var assemblyName = option.AssemblyName;
  42.                 var className = option.ClassName;
  43.                 var methodName = option.MethodName;
  44.                 var assembly = Assembly.Load(assemblyName);
  45.                 var classType = assembly.GetType(className)!;
  46.                 var methodInfo = classType.GetTypeInfo().GetDeclaredMethod(methodName)!;
  47.                 object? instance = null;
  48.                 if (!methodInfo.IsStatic)
  49.                 {
  50.                     instance = Activator.CreateInstance(classType);
  51.                 }
  52.                 object? result = methodInfo.Invoke(instance, null);
  53.                 _ = result;
  54.             })
  55.             .Run();
  56.         _ = result;
  57.         return true;
  58.     }
  59. }
  60. internal class RemoteExecutorOption
  61. {
  62.     public const string CommandName = "RemoteExecutor_F6679170-3719-49AB-9936-7CAB5AB6294D";
  63.     [Option]
  64.     public required string AssemblyName { get; init; }
  65.     [Option]
  66.     public required string ClassName { get; init; }
  67.     [Option]
  68.     public required string MethodName { get; init; }
  69. }
复制代码
本文代码放在 github 和 gitee 上,可以使用如下命令行拉取代码。我整个代码仓库比较庞大,使用以下命令行可以进行部分拉取,拉取速度比较快
先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
  1. git init
  2. git remote add origin https://gitee.com/lindexi/lindexi_gd.git
  3. git pull origin a3a10076765bea695136442c8745d18b42d840f2
复制代码
以上使用的是国内的 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码。如果依然拉取不到代码,可以发邮件向我要代码
  1. git remote remove origin
  2. git remote add origin https://github.com/lindexi/lindexi_gd.git
  3. git pull origin a3a10076765bea695136442c8745d18b42d840f2
复制代码
获取代码之后,进入 Workbench/DurwerjeguCalldemrereher 文件夹,即可获取到源代码

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册