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

访问Process类属性时如何避免‘拒绝访问’错误?

问题描述

我在C#中写了一个GetPropertyValues辅助方法,用来把对象属性转成键值对形式的Dictionary,代码如下:

public static Dictionary<string, object?> GetPropertyValues(object obj, int currentLevel = 0, int maxLevel = 3)
{
    Dictionary<string, object?> propertyValues = new Dictionary<string, object?>();
    if (currentLevel >= maxLevel)
    {
        propertyValues.Add("currentLevel", currentLevel);
        propertyValues.Add("maxLevel", maxLevel);
        return propertyValues;
    }
    foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(obj))
    {
        string name = descriptor.Name;
        object? value = descriptor.GetValue(obj);
        if (value != null)
        {
            if (!value.GetType().IsPrimitive)
            {
                value = GetPropertyValues(value, ++currentLevel, maxLevel);
            }
        }
        propertyValues.Add(name, value);
    }
    return propertyValues;
}

但传入System.Diagnostics.Process实例时,执行object? value = descriptor.GetValue(obj);会抛出异常:

Property accessor 'SafeHandle' on object 'System.Diagnostics.Process' threw the following exception:'Access is denied.'

Visual Studio调试器也显示同样的错误。我希望找到不依赖try/catch异常驱动的原生方法,来避免该错误或跳过会抛出异常的属性。

解决方案

.NET原生没有直接提供预判属性是否会抛出异常的API,但可以通过属性元数据、已知规则来筛选可安全访问的属性,以下是两种可行方案:

方案1:跳过已知的敏感属性

对于Process这类系统类,提前排除已知会触发权限问题的属性,适合明确知道问题属性的场景:

public static Dictionary<string, object?> GetPropertyValues(object obj, int currentLevel = 0, int maxLevel = 3)
{
    Dictionary<string, object?> propertyValues = new Dictionary<string, object?>();
    if (currentLevel >= maxLevel)
    {
        propertyValues.Add("currentLevel", currentLevel);
        propertyValues.Add("maxLevel", maxLevel);
        return propertyValues;
    }

    // 定义需要跳过的属性名单
    var excludedProperties = new HashSet<string> { "SafeHandle", "Handle" };

    foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(obj))
    {
        if (excludedProperties.Contains(descriptor.Name))
            continue;

        string name = descriptor.Name;
        object? value = descriptor.GetValue(obj);
        if (value != null)
        {
            // 注意不要直接++currentLevel,避免递归修改外层循环的层级变量
            if (!value.GetType().IsPrimitive && value.GetType() != typeof(string))
            {
                value = GetPropertyValues(value, currentLevel + 1, maxLevel);
            }
        }
        propertyValues.Add(name, value);
    }
    return propertyValues;
}

方案2:通过属性元数据筛选可安全访问的属性

通过检查属性的可浏览性、getter方法的公开性,过滤掉潜在的问题属性:

public static Dictionary<string, object?> GetPropertyValues(object obj, int currentLevel = 0, int maxLevel = 3)
{
    Dictionary<string, object?> propertyValues = new Dictionary<string, object?>();
    if (currentLevel >= maxLevel)
    {
        propertyValues.Add("currentLevel", currentLevel);
        propertyValues.Add("maxLevel", maxLevel);
        return propertyValues;
    }

    foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(obj))
    {
        // 跳过不可浏览的属性
        var browsableAttr = descriptor.Attributes[typeof(BrowsableAttribute)] as BrowsableAttribute;
        if (browsableAttr != null && !browsableAttr.Browsable)
            continue;
        
        // 跳过无公开getter的属性
        if (!descriptor.CanRead || descriptor.GetGetMethod() == null || !descriptor.GetGetMethod().IsPublic)
            continue;

        string name = descriptor.Name;
        object? value = descriptor.GetValue(obj);
        if (value != null)
        {
            if (!value.GetType().IsPrimitive && value.GetType() != typeof(string))
            {
                value = GetPropertyValues(value, currentLevel + 1, maxLevel);
            }
        }
        propertyValues.Add(name, value);
    }
    return propertyValues;
}

额外注意点

  • 原代码中++currentLevel存在逻辑问题:递归时直接递增会修改外层循环的层级变量,导致后续属性的递归层级错误,改为currentLevel + 1传递即可避免。
  • 上述方案能覆盖大部分常见场景,但无法处理所有未知的异常属性。如果要彻底兼容所有情况,还是需要给单个属性的读取逻辑加try/catch兜底,但这不属于“异常驱动”,只是局部容错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 11:35:38