强制转换接口和类对象
本文关键字:对象 接口 转换 | 更新日期: 2023-09-27 18:02:48
将对象强制转换为接口将对象强制转换为类的区别是什么?
namespace ConsoleApplication1
{
interface IAnimal
{
string Sound();
}
class Animal : IAnimal
{
public string Sound()
{
return "Animal sound";
}
}
class Lion : Animal, IAnimal
{
public string Sound()
{
return "Roarrrrr";
}
}
class Program
{
static void Main(string[] args)
{
Lion lion = new Lion();
IAnimal animal = (Animal)lion; // variant 1
IAnimal animal2 = (IAnimal)lion; // variant 2
Console.WriteLine(animal.Sound());
}
}
}
变量1和变量2的区别是什么?
唯一的区别在于编译器如何检查强制类型转换是否被允许。
在第一个变体中,编译器检查Lion
如何可以强制转换为Animal
,然后检查Animal
如何可以强制转换为IAnimal
。由于Lion
是Animal
, Animal
是IAnimal
,所以这两种类型的强制转换都是安全的,编译器根本不生成用于强制转换的代码,它只是一个赋值。
在第二个变体中,编译器检查Lion
如何可以强制转换为IAnimal
,然后检查IAnimal
是否与IAnimal
相同。因为强制转换可以安全地完成,所以它也不生成用于强制转换的代码,它也只是一个赋值。
因为Lion
是一个IAnimal
,你根本不需要做任何类型转换,你可以把它赋值给变量:
IAnimal animal3 = lion;
在这种情况下,编译器将检查Lion
如何可以强制转换为IAnimal
,因为这可以安全地完成,它不生成任何强制转换代码,只是赋值。
In
IAnimal animal = (Animal)lion;
存在隐式转换,因为animal
被声明为IAnimal
,而Animal
可转换为IAnimal
(因为类实现了该接口)。
对应于
Lion lion = new Lion();
Animal a = lion;
IAnimal ia = a;
所有这些转换都是可能的。
但是,你也可以这样写:
IAnimal lion = new Lion();
另一方面,如果你写了
var animal = (Animal)lion;
animal
应该是Animal
的一个实例。
从字面上看,在编译后的il中没有差异,但是当您将Animal
赋值给IAnimal
时,编译器会执行隐式转换。编译器很乐意这样做,因为它知道Animal
实现了IAnimal
。
这是IL,它显示了我的意思。
IL_0001: newobj UserQuery+Lion..ctor //Create new lion
IL_0006: stloc.0 // store it in variable lion
IL_0007: ldloc.0 // load variable lion
IL_0008: stloc.1 // store it in variable animal
IL_0009: ldloc.0 // load variable lion
IL_000A: stloc.2 // store it in variable animal2
IL_000B: ldloc.1 // load variable animal
IL_000C: callvirt UserQuery+IAnimal.Sound //Call animal.Sound
IL_0011: call System.Console.WriteLine //With the result call Console.WriteLine
在您的第一个示例中,您正在执行显式转换到Animal
,然后进行隐式转换,将其转换为类似于IAnimal animal = (IAnimal)(Animal)lion;
的IAnimal
。第二个示例只是执行隐式转换,出于各种目的,您可以删除第二个示例中的强制转换。