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

C# TargetInvocationException@PropertyInfo.GetValue(target,null),目标类型为MemoryStream,c#,reflection,properties,C#,Reflection,Properties,我想读取对象的所有公共属性值,并编写了以下代码: private List<PropertyInfo> GetListOfProperties(object objectToRegister, BindingFlags bindingFlags = BindingFlags.Instance | Bin

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

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;
}
例外情况如下所示

System.InvalidOperationException:此流不支持超时。在 System.IO.Stream.get_ReadTimeout()


现在,我想从
GetListOfProperties

的返回值中排除这些不受支持的属性,我认为您的代码本身是正常的

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

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

  • 对象可能有一个属性
    HasValue
    ,该属性指定是否可以查询另一个属性
    (或者这是否会导致
    无效操作异常
    或类似情况)

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

  • 在对对象执行任何操作之前,可能必须先对其进行
    初始化
    -d

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

如果您必须让反射代码与任何类型一起工作,以下是一些选项:

  • 最简单的方法是简单地“忽略”任何错误,方法是将对
    propertyInfo.GetValue
    的调用包装在
    try
    /
    catch
    块中(并可能将所有捕获的异常收集到
    aggregateeexception

  • 如果您希望以不同的方式处理某些特定类型以解决特定问题(如您的案例中的
    MemoryStream
    ),则可以创建反射代码的各种实现,并根据对象的
    类型选择策略。下面是一个非常粗糙的示例,让您了解:

    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
    
    接口IPropertyInspector
    {
    PropertyInfo[]获取属性(对象obj);
    }
    类GenericPropertySpector:IPropertySpector{/*您当前的实现*/}
    类StreamPropertyInspector:IPropertyInspector{/*不返回,例如,如果CanTimeout为false,则返回ReadTimeout*/}
    字典检查员=。。。;
    检查员[类型(MemoryStream)]=新的StreamPropertyInspector();
    ...
    类型t=objectToRegister.GetType();
    知识产权检查员;
    如果(!inspector.TryGetValue(t,out inspector))
    {
    inspector=新的GenericPropertyInspector();
    }
    var properties=inspector.GetProperties(objectToRegister):
    //对财产做些什么
    
    这样一个附加的间接级别将允许您过滤掉已知会导致问题的属性


  • 为什么要将
    declaringInstance
    (这是什么?)传递给
    propertyInfo.GetValue
    (而不是
    objectToRegister
    ?@stakx
    objectToRegister
    是一个
    MemoryStream
    GetValue
    需要他的类的实例。问题似乎与您的反射代码无关。您使用
    MemoryStream
    做什么?添加代码。@Yuval:我可以看到
    objectToRegister
    是;我问的是关于
    declaringInstance
    @stakx你说得对,
    declaringInstance
    只是复制/粘贴失败。我把它改为
    objectToRegister
    Stream
    类的属性称为
    CanRead
    CanTimeout
    CanSeek
    CanWrite
    用于指示是否可以调用其他属性/方法。更好的设计是返回某种类型的
    ,而不是抛出异常,但事实就是这样(而且永远不会改变),因此值得考虑stakx建议。目前,
    try/catch
    块是我的解决方法。我有一个问题,即MemoryStream不是通过我的代码的唯一类型。但是,这个无用异常的出现将使将来调试代码的难度加大。我希望找到一个类似
    IsSuppor的属性ted
    来整理这些属性,但只要我在这个方向上找不到任何东西,我就会接受这个答案。@Markus:对于任何属性和任何类型,都不存在通用的
    问题
    。对于
    s,你能得到的最接近的就是Ivan在上面的评论中提到的内容。
    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