我正在尝试通过转换Action<T>[]
的返回值(类型为Delegate.GetInvocationList
)从某个方法返回Delegate[]
类型的对象。尝试这样做时会抛出异常。
以下示例演示了我在一些更大的代码中尝试实现的目标:
using System;
class Fish
{ }
class FishDishes
{
public static void DishA(Fish f) { Console.WriteLine("Dish A"); }
public static void DishB(Fish f) { Console.WriteLine("Dish B"); }
}
class FishSchef
{
protected Action<Fish> cookFishDish = null;
public void ShowOff()
{
System.Console.WriteLine("cooking every fish dish I know of!");
cookFishDish?.Invoke(new Fish());
}
public void LearnToCookNewDish(Action<Fish> new_dish)
{
cookFishDish += new_dish;
}
}
class SeniorFishSchef : FishSchef
{
// Mentor a Junior Schef by sending her an array of every dish Senior Schef knows of
public Action<Fish>[] MentorJuniorSchef()
{
return (Action<Fish>[]) cookFishDish.GetInvocationList();
}
}
class JuniorFishSchef : FishSchef
{
// Get mentored by a Senior Schef by adding sending her an array of every dish Senior Schef knows of
public void GetMentored(SeniorFishSchef senior)
{
Action<Fish>[] dishes_arr = senior.MentorJuniorSchef();
foreach (Action<Fish> fishdish in dishes_arr)
cookFishDish += fishdish;
}
}
class Test
{
public static void Main()
{
SeniorFishSchef senior = new SeniorFishSchef();
senior.LearnToCookNewDish(FishDishes.DishA);
senior.LearnToCookNewDish(FishDishes.DishB);
senior.ShowOff();
JuniorFishSchef junior = new JuniorFishSchef();
junior.GetMentored(senior);
junior.ShowOff();
}
}
运行时,会抛出以下异常:
未处理的异常:System.InvalidCastException:无法转换类型的对象 'System.Delegate []'输入'System.Action`1 [Fish] []'。 在SeniorFishSchef.MentorJuniorSchef()[等等]
请帮助我理解:
为什么不能进行这样的演员表?
为什么编译器没有发出错误?
投射类型的符号是System.Action`1[Fish][]
- 为什么它有两个下标([][]
)?
注意:除了对上述问题的答案之外,还欢迎其他选择,但必须保护代表。我所知道的只是从MentorJuniorSchef返回Delegate[]
,并使dishes_arr
成为同一类型。
答案 0 :(得分:1)
1.为什么这样的演员不可能?
因为数组类型System.Delegate[]
与System.Action<Fish>[]
不同,也不能将其隐式转换为另一个。请注意,在C#中,有一种类型方差的形式允许隐式转换到另一个方向(即从Action<Fish>[]
到Delegate[]
),因为它保证了每个Action<Fish>
元素Action<Fish>[]
的实例实际上也是Delegate
。但是从Delegate
到Action<Fish>
,没有其他保证,所以尝试将Delegate[]
转换为Action<Fish>[]
是非法的。
2.为什么编译器不会发出错误?
当您编写显式强制转换时,编译器通常会假定您知道自己在做什么。它通常只会发出一个错误,如果它确实知道 ,那么演员表会失败(一个值得注意的例外涉及泛型,但是将这一点拖到讨论中会分散注意力。)
请注意,因为从Action<Fish>[]
转换为Delegate[]
是合法的(参见上文),实际上您可以使用Delegate[]
引用实际引用{{1}的实例1}}。所以在某些情况中,您尝试执行的转换可能会成功,因此编译器无法为其发出错误。
当然,在这种特殊情况下,数组实际上只是Action<Fish>[]
而不是Delegate[]
,因此是运行时错误。但编译器无法确定是否会出现这种情况。
3.投射类型的符号是
Action<Fish>[]
- 为什么它有两个下标(System.Action`1[Fish][]
)?
[][]
周围的方括号不是数组表示法,而是表示泛型Fish
的类型参数是什么的方法。未构造的类型名称显示为Action<T>
,其中Action`1
表示具有一个类型参数的泛型类型。第二组方括号 do 表示数组类型。
是的,这有点令人困惑。
至于替代方案,你当然可以返回一个新数组,你已经复制了原始元素。一个简单的方法是:
`1
由于您知道单个return cookFishDish.GetInvocationList().Cast<Action<Fish>>().ToArray();
对象实际上必须是Delegate
的实例,因此使用Action<Fish>
方法逐个转换每个对象,然后将生成的Enumerable.Cast<T>()
对象转换回来一个数组应该完成你想要的。