无法强制转换系统类型的对象.委托[]类型System.Action[T][]
本文关键字:类型 委托 System Action 对象 转换 系统 | 更新日期: 2023-09-27 18:05:40
我试图通过转换Delegate.GetInvocationList
的返回值,从某种方法返回Action<T>[]
类型的对象,这是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();
}
}
运行时,抛出以下异常:
Unhandled Exception: System。InvalidCastException:无法转换类型的对象的系统。委托[]'类型'System.Action ' 1[Fish][]'。@ SeniorFishSchef.MentorJuniorSchef()[等等等等]
请帮我理解:
为什么这样的cast是不可能的?
为什么编译器不发出错误?
转换类型的符号是
System.Action`1[Fish][]
-为什么它有两个下标([][]
)?
注意:除了上述问题的答案之外,还欢迎其他选择,但必须保护委托。我知道的一种方法是简单地从MentorJuniorSchef返回Delegate[]
,并使dishes_arr
具有相同的类型。
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[]
是合法的(见上文),所以实际上可以有一个真正引用Action<Fish>[]
实例的Delegate[]
引用。因此,在某些情况下,您尝试进行的强制转换可能会成功,因此编译器不会为它发出错误。
当然,在这种特殊情况下,数组实际上只是Delegate[]
而不是Action<Fish>[]
,因此出现了运行时错误。但是编译器无法确定是否会出现这种情况。
3。转换类型的符号是
System.Action`1[Fish][]
-为什么它有两个下标([][]
)?
Fish
周围的方括号不是数组表示法,而是指示泛型Action<T>
的类型参数的一种方法。未构造的类型名称显示为Action`1
,其中`1
表示具有一个类型参数的泛型类型。第二组方括号表示数组类型。
是的,这有点令人困惑。
至于替代方法,当然可以只返回一个新数组,其中从原始数组复制了元素。一个简单的方法是:
return cookFishDish.GetInvocationList().Cast<Action<Fish>>().ToArray();
由于您知道单个Delegate
对象实际上必须是Action<Fish>
的实例,因此使用Enumerable.Cast<T>()
方法单独转换每个对象,然后将结果IEnumerable<Action<Fish>>
对象转换回数组应该可以实现您想要的效果。