1

Context

I have an abstract parent class, Register, and two interfaces which require the implementation of the generic delegates Func<T> and Action<T> respectively:

public abstract class Register
{
    public int Address { get; protected set; }
    public string ID { get; protected set; }

    public abstract Type TargetType { get; }
    public abstract bool TargetIsArray { get; }
}

public interface IReadableRegister<T>
{
    Func<T> GetAccessor { get; }
}

public interface IWritableRegister<T>
{
    Action<T> SetAccessor { get; }
}

These are used to define a number of sub-classes, such as:

public class FooRegister<T> : Register, IReadableRegister<T>
{
    public override Type TargetType => typeof(T);
    public override bool TargetIsArray => TargetType.IsArray;
    public Func<T> GetAccessor { get; }
    // Further unique members

    public FooRegister(int address, object target, PropertyInfo targetProperty)
    {
        this.Address = address;
        this.ID = targetProperty.Name;
        this.GetAccessor = (Func<T>)targetProperty.GetMethod.CreateDelegate(typeof(Func<T>),target);
    }
}

public class BarRegister<T> : Register, IWritableRegister<T>
{
    public override Type TargetType => typeof(T);
    public override bool TargetIsArray => TargetType.IsArray;
    public Action<T> SetAccessor { get; }
    // Further unique members

    public BarRegister(int address, object target, PropertyInfo targetProperty)
    {
        this.Address = address;
        this.ID = targetProperty.Name;
        this.SetAccessor = (Action<T>)targetProperty.SetMethod.CreateDelegate(typeof(Action<T>),target);
    }
}

Usage

Using reflection, I build a List<Register> which ultimately provides a collection Get/Set delegates for the public properties of a target object (by a number a criteria irrelevant to this question). I wish to be able to index this List<Register> by ID (easily done) in order to then invoke the GetAccessor and/or SetAccessor as required.

Problem

I have so far failed to handle an element returned from the List<Register> as the specific generic type it was upon addition, since any cast requires me to use the variable Register.TargetType and generics must be typed at compile time.

Question(s)

I am aware of possible solutions to the issue such as that detailed here Setting generic type at runtime and also dynamic usage, however I feel that my approach is fundamentally flawed. How else might this functionality be achieved? Surely generics with polymorphic types are regularly handled?

George Kerwood
  • 1,248
  • 8
  • 19
  • @OlivierRogier It's likely a phase I've coined in my own ignorance but in this case I simply mean types that inherit from a common "parent" type. Much like the second answer provided to the question you provided above. Please do suggest/execute edits if this term is incorrect. – George Kerwood Jan 04 '21 at 10:04
  • @OlivierRogier Well, yes and no. The "polymorphic" significance here is that my usage requires me to have a `List` AND handle elements of that list as their specific generic type. That's the crux of the issue. To my mind, this is polymorphism, and in exhibiting polymorphism, they are are "polymorphic types"... but yes this is achieved through class hierarchy. – George Kerwood Jan 04 '21 at 10:18
  • 1
    @OlivierRogier Right, thank you very much. I apricate the correction without condescendence. I see my misunderstanding now. Your examples here enable me to contain all children of `Register` within a `List` (as I already can with my implementation), my difficulty is the inverse. How can I return an element from `List` as, for example, a `FooRegister`? – George Kerwood Jan 04 '21 at 10:34
  • Does this answer your question? [How to create List of open generic type of class?](https://stackoverflow.com/questions/58570948/how-to-create-list-of-open-generic-type-of-classt) and [How to do generic polymorphism on open types in C#?](https://stackoverflow.com/questions/58247604/how-to-do-generic-polymorphism-on-open-types-in-c/58247676) –  Jan 04 '21 at 10:36
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/226812/discussion-between-george-kerwood-and-olivier-rogier). – George Kerwood Jan 04 '21 at 10:39
  • 1
    I don't have time to chat, sorry. You need to create non-generic interface like `IRegister` which has common data and behaviors for the polymorphism. Your class hierarchy will implement this interface, in addition to others. So you can declare a `List` to be able to use polymorphism on its elements as samples from duplicates. I don't know how to do it another way because C# doesn't support the true-generic polymorphic diamond operator `<>` on open types applied to this. I look forward for us to be able to use it. –  Jan 04 '21 at 10:44
  • I see. The trouble is that fundamentally I had wanted to support generics due to the `Func` and `Action` members. Perhaps I'll substitute them for `Func` and `Action` or consider a different approach entirely. You've been hugely helpful, thank you greatly for your time. – George Kerwood Jan 04 '21 at 10:47
  • It does not solve the problem because you can't use polymorphism on a list having generic childs... You need to lost the genericity to apply polymorphism on a List because `List>` does not match at all with `List>`. It can't without the diamond operator. The only solution I know is to declare a `List` or `List`. So all generic types implements this interface or inherit from the class can be putted in the list. –  Jan 04 '21 at 10:49
  • 1
    It would remove the requirement for generics entirely. The root of the issue the generic delegates. – George Kerwood Jan 04 '21 at 10:51
  • Yes, unless someone has another solution never yet developed with current technology. You can use `Register` as you done, or an interface if it can help (I don't really read your code), but you must lost the genericity to do polymorphism on a list or any collection. It's annoying... so limiting. –  Jan 04 '21 at 10:52
  • I fought with it for a day and I can see from your contributions that it's a challenge you're very familiar with! It's annoying indeed, thank you again. – George Kerwood Jan 04 '21 at 10:56
  • This topic generates many questions, more and more because it poses a problem with lists and collections, but this topic is not really developed. Java first introduced the [diamond operator](https://en.wikipedia.org/wiki/Generics_in_Java#Diamond_operator) to solve this design need, but they haven't gotten there yet, it seems, because it remained at the stage of simplifying the declarations of variables, nothing more, as it was taken again in C# recently. You will hear about co and contra variance, but that avoids the problem. –  Jan 04 '21 at 11:02

0 Answers0