【问题标题】:How to declare a list of Action<T> that can manage differents generic type parameters? [duplicate]如何声明可以管理不同泛型类型参数的 Action<T> 列表? [复制]
【发布时间】:2020-07-14 14:05:35
【问题描述】:

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

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>>() 

它返回 T 不存在。

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

【问题讨论】:

  • 如果您在方法中声明列表,它应该可以工作。否则,你需要让你的类通用:class MyClass&lt;T&gt;
  • 声明整个类是通用的。但是如果你需要处理不同的类型,泛型可能不是最好的解决方案
  • 您希望能够将这两种类型添加到同一个列表中吗?
  • @Knoop 没错!
  • 使用Action&lt;object&gt; 进行强制转换可能会有所帮助

标签: c# list generics delegates polymorphism


【解决方案1】:

C# 中没有菱形运算符 &lt;&gt;,而且 .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

【讨论】:

    【解决方案2】:

    鉴于 OP 的这一要求,即他需要能够将不同的类型存储在同一个列表中(byte[]bool),主要有三种方法可以做到这一点。

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

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

    第三,这是代码最不臭的方法,创建一个包含byte[]bool 属性的struct,并将您的数据分配给两者之一,然后将您的结构传递给行动。没有更多的强制转换尝试,只需检查各个属性是否为null。这更类似于 C++ std::any&lt;&gt;

    【讨论】:

      猜你喜欢
      • 2012-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-10
      • 2016-01-01
      相关资源
      最近更新 更多