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
?@stakxobjectToRegister
是一个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