Search code examples
c#listgenericsdelegatespolymorphism

How to declare a list of Action<T> that can manage differents generic type parameters?


I have a method that receives and action (previously was action < bool >, but now I need more types allowed):

public void Runaction<T>(Action<T> _ActionCallback)
{  
 StackAction.Add(_ActionCallback);
    ...etc
}

Previously, my list stackAction was:

readonly List<Action<bool>> StackAction=  new List<Action<bool>>() 

But now I need this list to allowed type bool but byte[] too

When I declare

readonly List<Action<T>> StackAction=  new List<Action<T>>() 

it returns T does not exists.

What is the workaround for this need?


Solution

  • There is no diamond operator <> in C# and .NET does not support true generic polymorphism on open types yet.

    Generics open and closed constructed types

    Thus we can't write:

    readonly List<Action<>> StackAction = new List<Action<>>();
    

    To allow a list of action of any one type parameter.

    Moreover, this case of true generic polymorphism on delegates is more complicated to manage compared to classes or interfaces or value types.

    But you can manage each type you want like that:

    public class MyClass
    {
      private readonly List<object> StackAction = new List<object>();
    
      public void Runaction<T>(Action<T> _ActionCallback)
      {
        switch ( _ActionCallback )
        {
          case Action<bool> action:
            StackAction.Add(action);
            action(GetBoolParameter());
            break;
          case Action<byte[]> action:
            StackAction.Add(action);
            action(GetByteArrayParameter());
            break;
          default:
            string message = $"Type not supported for Runaction<T>." + Environment.NewLine
                           + $"Only bool or byte[] is allowed." + Environment.NewLine
                           + $"Type provided: {typeof(T).Name}";
            throw new ArgumentException(message);
        }
      }
    
      private bool GetBoolParameter()
      {
        return false;
      }
    
      private byte[] GetByteArrayParameter()
      {
        return new byte[] { 1, 2, 3, 4, 5 };
      }
    }
    

    Test

    Action<bool> actionBool = value =>
    {
      Console.WriteLine(value.GetType());
    };
    Action<byte[]> actionByteArray = value =>
    {
      Console.WriteLine(value.GetType());
    };
    Action<int> actionInt = value =>
    {
      Console.WriteLine(value.GetType());
    };
    
    var instance = new MyClass();
    
    instance.Runaction(actionBool);
    instance.Runaction(actionByteArray);
    
    try
    {
      instance.Runaction(actionInt);
    }
    catch ( Exception ex )
    {
      Console.WriteLine(ex.Message);
    }
    

    Output

    System.Boolean
    System.Byte[]
    
    Type not supported for Runaction<T>.
    Only bool or byte[] is allowed.
    Type provided: Int32