如何声明可以管理不同泛型类型参数的 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
我有一个接收和动作的方法(以前是动作
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