FastMember ObjectReader doesn't work with inherited interfaces
Asked Answered
G

1

3

I get an interface as return from a library that I have no control over:

public interface IA : IB { String A { get;} }
public interface IB { String B { get;} }

Now when I try to run this code, I get an exception:

List<IA> list = library.Get();
IDataReader r = ObjectReader.Create(list, nameof(IA.A), nameof(IA.B));
while (r.Read())
{
    for (Int32 i = 0; i < r.FieldCount; i++)
    {
        //HERE ArgumentOutOfRangeException: Specified argument was out of the range of valid values.Parameter name: name
        Object o = r[i];
        Console.Write(o + ",");
    }
    Console.WriteLine();
}

It seems like it doesn't find the B property because it's declared in IB. I confirmed this by making a test and having B in IA directly.

I have found a very bad workaround, which involves creating a new class that implements IA:

public class Ab : IA
{
    public Ab(String a, String b)
    {A = a;B=b;}

    public String A { get;}
    public String B { get;}
}

and then convert the List<IA> as such: List<Ab> newList = l.Select(e => new Ab(e.A, e.B).ToList(), then ObjectReader.Create(newList). ObjectReader seems to find the B property when I do this. But that seems very wasteful on resources (and a lot of code) to create this intermediary objects with the exact same content.

Any idea if it's possible to solve in another way that doesn't involve creating new objects?

Gerhan answered 20/12, 2016 at 11:19 Comment(1)
You could always open an issue? This sounds like a plain old bug to me. Interfaces do require special attention because, internally, their members don't inherit the way they do for classes, but I should think FastMember is supposed to handle that.Celery
I
2

I cloned the Repository of the FastMember Package, in the TypeAccessor class I changed line 265 from:

PropertyInfo[] props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);

to:

PropertyInfo[] props = GetPrpsInterfaces(type, BindingFlags.Public | BindingFlags.Instance).ToArray();

The Implementation of the replacing function:

static IEnumerable<PropertyInfo> GetPrpsInterfaces(Type type, BindingFlags flags)
{
      if (!type.IsInterface)
           return type.GetProperties(flags);

      return (new Type[] { type }).Concat(type.GetInterfaces()).SelectMany(i => i.GetProperties(flags));
}

I found here: GetProperties() to return all properties for an interface inheritance hierarchy

This worked for me.

Informant answered 20/7, 2018 at 13:46 Comment(2)
FYI - I used your answer to create a PR for fast-member. There's an additional bit of code that needs to be changed at line 17 of MemberSet.cs -- it's the same kind of change. You can look at my PR github.com/mgravell/fast-member/pull/63/filesTranscaucasia
Thanks and sorry for being late, I hope your request will be contained in the next version.Informant

© 2022 - 2024 — McMap. All rights reserved.