mardi 8 décembre 2020

Get subclass properties from list of superclass

I have a method that will convert a List<T> into a TSV string with a header row and will only have rows which have a value for any item in the list. What I was doing previously was getting the type of T and working off that. My problem now, it that my list will no longer contain an item of type T, but something that derives from the type of the list. So doing typeof(T).GetProperties() will no longer work because that's looking at the parent type and not the child type.

public static string ListToTSVString<T>(List<T> items)
{
    StringBuilder builder = new StringBuilder();
    PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);

    // Get only properties that actually have a value in the list.
    var propsDictionary =
        properties.ToDictionary(p => p, p => items.Select(l => p.GetValue(l)).ToArray())
            .Where(pair => pair.Value.Any(o => o != null))
            .ToDictionary(pair => pair.Key, pair => pair.Value);

    // Header row
    builder.AppendLine(string.Join("\t", propsDictionary.Keys.Select(x => x.GetCustomAttribute<JsonPropertyAttribute>().PropertyName)));

    // Body of TSV
    foreach (T item in items)
    {
        builder.AppendLine(string.Join("\t", propsDictionary.Keys.Select(x => x.GetValue(item))));
    }

    // Remove new line character
    return builder.ToString().TrimEnd();
}

As an example of something I am passing in is:

public class CustomObject
{
    public string GUID { get; set; }
}

public class Referral : CustomObject
{
    public string Name { get; set; }
}

I'd then call this with a: List<CustomObject> objects = new List<CustomObject> { new Referral() { Name = "Jimenemex" } }.

I'm trying to get the TSV string to now contain only the declared properties on the Referral type and not the CustomObject type. Before I was only working with an object that doesn't inherit from anything so this was working nicely.

I've tried to use items.GetType().GetGenericArguments()[0], but that would still get the CustomObject type.





Aucun commentaire:

Enregistrer un commentaire