C# 无法将System.Delegate[]类型的对象强制转换为System.Action[T][]类型

C# 无法将System.Delegate[]类型的对象强制转换为System.Action[T][]类型,c#,casting,delegates,C#,Casting,Delegates,我试图通过强制转换Delegate.GetInvocationList的返回值,从某个方法返回Action[]类型的对象,该对象属于Delegate[]。尝试执行此操作时会引发异常 下面的示例演示了我试图在一些较大的代码中实现的目标: using System; class Fish { } class FishDishes { public static void DishA(Fish f) { Console.WriteLine("Dish A"); } public s

我试图通过强制转换
Delegate.GetInvocationList
的返回值,从某个方法返回
Action[]
类型的对象,该对象属于
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();
    }
}
使用系统;
分类鱼
{ }
鱼缸
{
公共静态无效DishA(Fish f){Console.WriteLine(“DishA”);}
公共静态无效DishB(Fish f){Console.WriteLine(“DishB”);}
}
FishSchef类
{
受保护操作cookFishDish=null;
公众虚张声势
{
System.Console.WriteLine(“烹饪我知道的每一道鱼菜!”);
烹饪鱼盘?.Invoke(新鱼());
}
公共空间学习烹饪新菜(行动新菜)
{
cookFishDish+=新的_盘;
}
}
类别:FishSchef
{ 
//指导一个初级Schef,向她发送一系列高级Schef知道的每道菜
公共行动[]导师JUnitorsChef()
{
return(Action[])cookFishDish.GetInvocationList();
}
}
类JuniorFishSchef:FishSchef
{ 
//得到高级Schef的指导,向她发送高级Schef知道的每道菜的数组
获得辅导的公共部门(高级Fishschef高级)
{
Action[]disks_arr=senior.MentorJuniorSchef();
foreach(盘子中的动作鱼盘)
烹饪鱼盘+=鱼盘;
}
}
课堂测试
{
公共静态void Main()
{
SeniorFishSchef senior=新的SeniorFishSchef();
高级烹饪新菜(Fishdisks.DishA);
高级烹饪新菜(fishdisks.DishB);
高级。炫耀();
JuniorFishSchef junior=新的JuniorFishSchef();
初级。获得指导(高级);
junior.shooff();
}
}
运行时,会引发以下异常:

未处理的异常:System.InvalidCastException:无法强制转换类型为的对象 “System.Delegate[]”以键入“System.Action'1[Fish][]”。 在SeniorFishSchef.MentorJuniorSchef()上[etc]

请帮助我理解:

  • 为什么这样的演员阵容不可能

  • 为什么编译器没有发出错误

  • 铸造类型的符号是什么?操作'1[Fish][]-为什么它有两个下标(
    []]

  • 注:除了回答上述问题外,还欢迎其他选择,但必须保护代表。据我所知,有一种方法就是从导师JUnitorsChef处返回
    Delegate[]
    ,并制作相同类型的
    carr

    1.为什么这样的演员阵容不可能

    因为数组类型
    System.Delegate[]
    System.Action[]
    不同,也不能将一个隐式转换为另一个。请注意,在C#中,存在一种类型差异形式,允许隐式转换到另一个方向(即从
    操作[]
    委托[]
    ),因为它保证
    操作[]
    实例中的每个
    操作
    元素实际上也是
    委托
    。但是,从
    委托
    操作
    ,没有这样的保证,因此试图将
    委托【】
    强制转换为
    操作【】
    ,是非法的

    2.为什么编译器不发出错误

    编写显式转换时,编译器通常假定您知道自己在做什么。它通常只有在确信强制转换将失败时才会发出错误(一个值得注意的例外涉及泛型,但将其拖到这里的讨论中会分散注意力)

    请注意,由于从
    操作[]
    转换为
    委托[]
    (见上文)是合法的,因此实际上您可以有一个真正引用
    操作[]
    实例的
    委托[]
    引用。因此,在某些情况下,您尝试执行的强制转换可能会成功,因此编译器无法为此发出错误

    当然,在这种特殊情况下,数组实际上只是
    Delegate[]
    ,而不是
    Action[]
    ,因此是运行时错误。但编译器无法确定情况是否如此

    3.强制类型的符号是什么
    System.Action`1[Fish][]
    -为什么它有两个下标(
    [][]

    Fish
    周围的方括号不是数组表示法,而是指示泛型类型
    Action
    的类型参数的一种方式。未构造的类型名称显示为
    Action`1
    ,其中
    `1
    表示具有一个类型参数的泛型类型。第二组方括号表示数组类型

    是的,有点混乱

    至于替代方案,您当然可以只返回一个新数组,其中您已经从原始数组中复制了元素。一个简单的方法是:

    return cookFishDish.GetInvocationList().Cast<Action<Fish>>().ToArray();
    
    返回cookFishDish.GetInvocationList().Cast().ToArray();
    
    由于您知道单个
    委托
    对象实际上必须是
    操作
    的实例,因此使用
    Enumerable.Cast()
    方法分别强制转换每个对象,然后将生成的
    IEnumerable
    对象转换回数组应该可以实现您想要的功能