访问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
相关产品推荐
相关产品推荐

