TargetInvocationException @ PropertyInfo.GetValue(target, null) 目标类型为 MemoryStream

TargetInvocationException @ PropertyInfo.GetValue(target, null) with Target Type MemoryStream

我想读取对象的所有 public 属性 值并编写了以下代码:

private List<PropertyInfo> GetListOfProperties(object objectToRegister,
                                BindingFlags bindingFlags = BindingFlags.Instance |
                                                            BindingFlags.Public)
{
    Type type = objectToRegister.GetType();
    List<PropertyInfo> curListOfProperties = new List<PropertyInfo>();
    curListOfProperties.AddRange(type.GetProperties()
                                    .Where((propertyInfo) =>
                                    !propertyInfo.GetIndexParameters().Any()));
    return curListOfProperties;
}

并这样称呼它:

var objectToRegister = new MemoryStream();

// ... eventually write things into MemoryStream e.g. Image.Save(objectToRegister , "Bmp") 
// ... eventually do nothing with objectToRegister 

foreach (var propertyInfo in GetListOfProperties(objectToRegister))
{
    if (propertyInfo.CanRead)
    {
        // -->> TargetInvocationException
        value = propertyInfo.GetValue(objectToRegister , null); 
    }
}

异常看起来像这样

System.InvalidOperationException: Timeouts are not supported on this stream. at System.IO.Stream.get_ReadTimeout()

现在我想从 GetListOfProperties

的 return 值中排除此类不受支持的属性

我觉得你的代码本身没问题。

但我怀疑您的方法存在一个基本的设计缺陷:即您假设您可以随时随地以任何顺序成功阅读任何 属性。

设计良好的类型可能会满足这个假设,但不幸的是,有些类型遵循不同的协议:

  • 一个对象可能有一个属性HasValue,指定是否可以查询另一个属性Value(或者这是否会导致InvalidOperationException 或类似的)。

    (设计更好的类型可能有 TryGetValue 方法或可为空的 Value 属性。)

  • 一个对象可能必须先 Initialize-d 才能对其进行任何操作。

等您在 Stream.ReadTimeout 中遇到了另一个这样的例子,显然 MemoryStream.

不支持它

如果您必须让反射代码与 任何 类型一起使用,这里有一些选项:

  1. 最简单的方法是通过将对 propertyInfo.GetValue 的调用包装在 try/catch 块中来简单 "ignore" 任何错误(也许将所有捕获的异常收集到 AggregateException).

  2. 如果您想以不同的方式对待某些特定类型以解决特定问题(例如 MemoryStream 的情况),您可以创建反射代码的各种实现并选择基于策略在对象的 Type 上。这是一个非常粗略的例子,可以给你一个想法:

    interface IPropertyInspector
    {
        PropertyInfo[] GetProperties(object obj);
    }
    
    class GenericPropertyInspector : IPropertyInspector { /* your current implementation */ }
    
    class StreamPropertyInspector : IPropertyInspector { /* does not return e.g. ReadTimeout if CanTimeout is false */ }
    
    Dictionary<Type, IPropertyInspector> inspectors = ...;
    inspectors[typeof(MemoryStream)] = new StreamPropertyInspector();
    
    ...
    Type t = objectToRegister.GetType();
    IPropertyInspector inspector;
    if (!inspectors.TryGetValue(t, out inspector))
    {
        inspector = new GenericPropertyInspector();
    }
    var properties = inspector.GetProperties(objectToRegister):
    // do something with properties
    

    这种额外的间接级别将允许您过滤掉已知会导致问题的属性。