简体   繁体   中英

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

I wanted to read all the public property values of objects and wrote following code:

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;
}

And call it like this:

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); 
    }
}

The Exception looks like this

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

Now I would like to exclude such unsupported Properties from the return value of GetListOfProperties

Your code by itself looks OK to me.

But I suspect that your approach has one fundamental design flaw: namely your assumption that you can read any property successfully, anytime, in any order.

Well-designed types might fulfill this assumption, but unfortunately there are types out there that follow different protocols:

  • An object may have a property HasValue , which specifies whether another propery Value may be queried (or whether that would result in an InvalidOperationException or similar).

    (A better-designed type might have a TryGetValue method or a nullable Value property instead.)

  • An object may have to be Initialize -d first before anything can be done with it.

etc. You came across another such example with Stream.ReadTimeout , which apparently simply isn't supported on MemoryStream .

If you have to get your reflection code to work with any type, here are some options:

  1. The easiest way is to simply "ignore" any errors by wrapping the call to propertyInfo.GetValue in a try / catch block (and perhaps collect all caught exceptions into an AggregateException ).

  2. If you want to treat some specific types differently to work around particular issues (like your case with MemoryStream ), you could create various implementations of your reflection code and choose a strategy based on an object's Type . Here's a very crude example to give you an idea:

     interface IPropertyInspector { PropertyInfo[] GetProperties(object obj); } class GenericPropertyInspector : IPropertyInspector { /* your current implementation */ } class StreamPropertyInspector : IPropertyInspector { /* does not return eg 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 

    Such an additional level of indirection would allow you to filter out properties that are known to cause problems.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM