最近我遇到了与投射有关的奇怪问题。我所看到的每一个讨论/帖子都倾向于围绕使用强制转换,当确定要渲染的对象加上一些细节时。然而,我没有找到下面代码背后的原因:
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> { }
}
那么为什么第二个调用抛出异常?我不知道铸造和操作员之间的区别是什么?
编辑: 它会在上面的注释行中抛出 “Unhandled Exception:System.InvalidCastException:无法将类型为'SomeCommandHandler'的对象强制转换为'ICommandHandler`1 [ConsoleApplication1.Program + ICommand]'”
答案 0 :(得分:9)
嗯,这就是那里的整个差异。如果对象无法转换为该类型,as
运算符将返回null
,并且只是转换会产生异常。
答案 1 :(得分:2)
其他人已经解释了直接投掷抛出异常和as
在投射失败时返回null
之间的区别。为了能够使这样的演员成功,你需要使通用接口逆变:
interface ICommandHandler<out I> where I : ICommand { }
然而,这可能是不可能的,这取决于界面的真实外观(我假设你为了简洁而展示了一个精简的版本)。如果你的接口包含接受I
类型的参数的方法,那么这将不起作用;类型I
必须仅出现在get-operations中:
interface ICommandHandler<out I> where I : ICommand
{
void SetCommand(I n); // this would not be allowed...
I GetCommand(); // ...but this would.
}
答案 2 :(得分:1)
它会抛出一个异常,因为h的类型为SomeCommandHandler
ICommandHandler<SomeCommand>
并且您尝试将其强制转换为ICommandHandler<ICommand>
,这是另一种类型。
答案 3 :(得分:0)
演员表失败,因为ICommandHandler<SomeCommand>
不是ICommandHandler<ICommand>
。有关详细信息,请参阅here。实例
当实例不是指定类型时,as
只返回null,而投射会抛出InvalidCastexception
答案 4 :(得分:0)
变量c是a为空。它不会抛出,因为这就是使用“as”的意思。换句话说,实例h不是ICommandHandler的实例。
下一行抛出是因为您试图强制将SomCommandHandler实例强制转换为ICommandHandler的实例
有意义吗?