You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将导入的System.Diagnostics.Process转为自定义ProcessChild子类?

问题描述

应用关闭后需要记住外部进程列表,因此将进程PID保存到文件,启动时重新导入。当使用System.Diagnostics.Process类型时,可通过Process.GetProcessById直接恢复进程实例,代码示例如下:

public List<Process> GetKnownProcesses()
{
    int[] saved_ids = { 1, 2, 3 };
    List<Process> known_processes = new List<Process>();
    foreach (int id in saved_ids)
    {
        known_processes.Add(Process.GetProcessById(id)); // 为简化示例省略异常处理
    }
    return known_processes;
}

但当前需要使用Process的子类ProcessChild(用于扩展功能),直接向下转换Process实例到ProcessChild不可行,且复制父类只读属性也无法实现,代码报错如下:

public class ProcessChild : Process
{
    // 扩展功能的代码
}

public List<ProcessChild> GetKnownProcesses()
{
    int[] saved_ids = { 1, 2, 3 };
    List<ProcessChild> known_processes = new List<ProcessChild>();
    foreach (int id in saved_ids)
    {
        known_processes.Add(Process.GetProcessById(id)); // 错误:需向下转换,但无法直接实现
    }
    return known_processes;
}

寻求无需自行编写完整GetProcessById逻辑的高效解决方案,是否有设置属性或调用更新方法的替代方式?

解决方案

1. 使用组合而非继承(推荐)

放弃继承Process,改为将Process作为ProcessChild的内部属性,通过封装来扩展功能。这种方式符合SOLID原则,避免继承带来的类型转换问题:

public class ProcessChild
{
    // 封装原生Process实例
    public Process UnderlyingProcess { get; }

    // 自定义扩展方法/属性
    public string CustomInfo => $"Process {UnderlyingProcess.Id}: {UnderlyingProcess.ProcessName}";

    public ProcessChild(Process process)
    {
        UnderlyingProcess = process ?? throw new ArgumentNullException(nameof(process));
    }
}

// 导入进程的方法
public List<ProcessChild> GetKnownProcesses()
{
    int[] saved_ids = { 1, 2, 3 };
    List<ProcessChild> known_processes = new List<ProcessChild>();
    foreach (int id in saved_ids)
    {
        var process = Process.GetProcessById(id);
        known_processes.Add(new ProcessChild(process));
    }
    return known_processes;
}

2. 通过反射复制属性(兼容继承场景)

如果必须保留继承关系,可以通过反射将Process实例的属性(包括只读属性对应的内部字段)复制到ProcessChild实例中。注意这种方式依赖.NET的内部实现细节,可能在版本更新时失效:

public class ProcessChild : Process
{
    // 扩展功能的代码
}

public static class ProcessExtensions
{
    public static ProcessChild ToProcessChild(this Process process)
    {
        if (process == null)
            throw new ArgumentNullException(nameof(process));

        var child = new ProcessChild();
        var processType = typeof(Process);

        // 遍历所有实例属性(包括非公开)
        foreach (var prop in processType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
        {
            if (prop.CanWrite)
            {
                // 可写属性直接赋值
                prop.SetValue(child, prop.GetValue(process));
            }
            else
            {
                // 只读属性尝试修改对应的私有字段(命名约定为_PropertyName)
                var field = processType.GetField($"_{prop.Name}", BindingFlags.Instance | BindingFlags.NonPublic);
                field?.SetValue(child, field.GetValue(process));
            }
        }

        return child;
    }
}

// 导入进程的方法
public List<ProcessChild> GetKnownProcesses()
{
    int[] saved_ids = { 1, 2, 3 };
    List<ProcessChild> known_processes = new List<ProcessChild>();
    foreach (int id in saved_ids)
    {
        var process = Process.GetProcessById(id);
        known_processes.Add(process.ToProcessChild());
    }
    return known_processes;
}

3. 封装静态获取方法

在ProcessChild中封装静态方法,内部调用Process.GetProcessById并通过反射初始化子类实例,把转换逻辑集中在子类内部:

public class ProcessChild : Process
{
    // 扩展功能的代码

    public static new ProcessChild GetProcessById(int id)
    {
        var baseProcess = Process.GetProcessById(id);
        var child = new ProcessChild();
        var processType = typeof(Process);

        // 复制属性逻辑同反射方案
        foreach (var prop in processType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
        {
            if (prop.CanWrite)
            {
                prop.SetValue(child, prop.GetValue(baseProcess));
            }
            else
            {
                var field = processType.GetField($"_{prop.Name}", BindingFlags.Instance | BindingFlags.NonPublic);
                field?.SetValue(child, field.GetValue(baseProcess));
            }
        }

        return child;
    }
}

// 导入进程的方法
public List<ProcessChild> GetKnownProcesses()
{
    int[] saved_ids = { 1, 2, 3 };
    List<ProcessChild> known_processes = new List<ProcessChild>();
    foreach (int id in saved_ids)
    {
        known_processes.Add(ProcessChild.GetProcessById(id));
    }
    return known_processes;
}

方法对比

  • 组合方式:最稳定、易维护,无版本兼容风险,优先推荐。
  • 反射方式:兼容继承场景,但依赖内部实现,维护成本高,仅在必须继承时使用。
  • 封装静态方法:和反射方式类似,但逻辑集中在子类,代码更整洁,同样存在版本兼容风险。

内容的提问来源于stack exchange,提问作者mrpiggy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 10:15:40