C# as运算符和铸造之间的差异(涉及泛型)

C# as运算符和铸造之间的差异(涉及泛型),c#,generics,casting,C#,Generics,Casting,最近我遇到了一个与铸造有关的奇怪问题。我所看到的每一篇讨论/帖子都倾向于围绕着使用施法来进行,当一个人确信要施法的对象以及一些细节时。然而,我还没有找到下面代码背后的原因: class Program { static void Main(string[] args) { var h = new SomeCommandHandler(); var c = h as ICommandHandler<ICommand>; //this wo

最近我遇到了一个与铸造有关的奇怪问题。我所看到的每一篇讨论/帖子都倾向于围绕着使用施法来进行,当一个人确信要施法的对象以及一些细节时。然而,我还没有找到下面代码背后的原因:

class Program
{
    static void Main(string[] args)
    {
        var h = new SomeCommandHandler();
        var c = h as ICommandHandler<ICommand>; //this works as expected
        //var c = (ICommandHandler<ICommand>)h; //this throws - why?
    }

    interface ICommand { }
    class SomeCommand : ICommand { }

    interface ICommandHandler<I> where I : ICommand { }
    class SomeCommandHandler : ICommandHandler<SomeCommand> { }
}
类程序
{
静态void Main(字符串[]参数)
{
var h=新的SomeCommandHandler();
var c=h作为ICommandHandler;//这可以正常工作
//var c=(ICommandHandler)h;//这会抛出-为什么?
}
接口ICommand{}
类SomeCommand:ICommand{}
接口ICommandHandler,其中I:ICommand{}
类SomeCommandHandler:ICommandHandler{}
}
那么为什么第二个调用会抛出异常呢?我不知道演员和演员之间有什么区别

编辑: 它可以在上面的注释行中插入
“未处理的异常:System.InvalidCastException:无法将类型为'SomeCommandHandler'的对象强制转换为类型为'ICommandHandler`1[ConsoleApplication1.Program+ICommand]'”

嗯,这就是全部区别所在。如果无法将对象强制转换为该类型,则
as
运算符返回
null
,仅强制转换会产生异常。

强制转换失败,因为
ICommandHandler
不是
ICommandHandler
。有关更多详细信息和示例,请参阅


当实例不是指定类型时,
as
只返回null,而强制转换抛出一个
InvalidCastexception

它抛出一个异常,因为h的类型是
SomeCommandHandler
,即
ICommandHandler
,您尝试将其强制转换为另一个类型的
ICommandHandler

变量c是一个null。它不会抛出,因为使用“as”就是这个意思。换句话说,实例h不是ICommandHandler的实例

下一行抛出,因为您正试图将SomCommandHandler实例强制转换为ICommandHandler实例


有意义吗?

其他人已经解释了抛出异常的直接强制转换与当强制转换失败时返回
null的
直接强制转换之间的区别。为了使此类转换成功,您需要使通用接口反向:

interface ICommandHandler<out I> where I : ICommand { }

@库珀-冒昧地猜测这是一个无效的例外……呃,我不知道我是怎么忽略了这一点的。我很确定示例中的“as”返回了非空值…猜一猜。我需要它作为参数(void Execute(SomeCommand cmd)),所以,正如您所说,协方差对我没有帮助。无论如何,谢谢你的帮助!
interface ICommandHandler<out I> where I : ICommand 
{
    void SetCommand(I n); // this would not be allowed...
    I GetCommand();       // ...but this would.
}