如何声明可以管理不同泛型类型参数的 Action<T> 列表?

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

我有一个接收和动作的方法(以前是动作,但现在我需要更多允许的类型):

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

之前,我的列表 stackAction 是:

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

但现在我需要这个列表来允许类型 bool 但 byte[] 也

当我声明时

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

它returnsT不存在

满足此需求的解决方法是什么?

鉴于 OP 的这一要求,他需要能够将不同的类型存储在同一个列表中(byte[]bool),可以通过三种主要方法来实现。

首先,使用 object 多态性并声明该类型的集合。这当然使它更难使用,因为您必须自己手动测试每种类型,并相应地访问它。

其次,与第一个类似,使用dynamic。这不会使用多态性,它会实例化一个编译器站点来根据需要处理正确的类型。如果你有某种类型的鸭子输入,这会更好,否则你将不得不尝试将其转换为 #1,这样你将不会获得任何东西,并且在此过程中会失去 Intellisense。

第三,这是代码臭味最少的方法,创建一个包含 byte[]bool 属性 的 struct,并将您的数据分配给两者之一,然后将结构传递给操作。没有更多的转换尝试,只是检查各个属性是否为 null。这更类似于 C++ std::any<>.

C# 中没有菱形运算符 <>,并且 .NET 尚不支持开放类型的真正通用多态性。

Generics open and closed constructed types

因此我们不能写:

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

允许任何一种类型参数的动作列表。

此外,与 类 或接口或值类型相比,这种委托上真正的泛型多态性的情况更难以管理。

但是您可以像这样管理您想要的每种类型:

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

测试

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

输出

System.Boolean
System.Byte[]

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