什么是对象投射?

关于究竟什么是对象转换以及它用于什么,我有点困惑。 我已经阅读了有关Casting和类型转换的MSDN文档,在那里我可以看到,对于显式转换,您需要使用强制转换运算符。 我理解文档中给出的示例,如果在将一种类型转换为另一种类型时可能会丢失一些数据,则需要使用强制转换运算符。

我只是对你如何投射物体感到困惑? 我假设对象是一个类的实例,它可能包含比简单数据类型更多的信息? 那么你需要如何,为什么以及何时投射物体?

我已经看到了一个抛出一个对象的例子,它简单地说:

SomeType name = (SomeType)obj; 

我错过了什么,还是这个对象投射? 如果是,在什么情况下你需要像这样投射一个对象?

当没有可用的隐式转换时,您只需要使用转换运算符,编译器可以validation它是否安全。 如果有一个并且编译器确定转换将成功,那么它将自动为您完成。

现在,我为什么要使用演员? 你应该使用演员:

  • 有一个A类型的对象,你需要一个B类型的对象,并且有一种方法可以将A转换为B
  • 对对象有类型A的引用,并且需要对同一对象引用类型B ,并且AB都是该对象的有效引用类型。

另一种思考方式是:

  • 如果您比编译器更了解并且您知道对象是编译器不能的类型。
  • 当某个对象不属于某种类型但您知道该类型的转换有效时。

这就提出了一种根据演员真正做的事情来分组演员表的方法:

  • 保持身份的演员。
  • 没有的演员。

第一组是我们所说的参考转换 。 这些根本不会更改对象,它们只是更改指向对象的引用类型(显然,它们仅适用于引用类型,值类型不能具有引用转换,因为您无法获取对值的引用类型)。 请注意,此类型的强制转换是由语言本身提供的,您无法实现参考转换。

第二组是所有需要在对象中进行表示更改的转换,也就是说,转换返回的对象的位与已转换对象的位不同。 这些类型的强制转换是您可以在任何C#类/结构中实现的implicitexplicit运算符。

您可以在此SO答案中阅读更多相关信息。

好的,这一切都非常有趣,但你能给我具体的例子吗? 当然是:

  1. 编译器足够了解:

     interface IFoo { } class Foo: IFoo { } IFoo foo = new Foo(); 

    在最后一个语句中有一个从FooIFoo的隐式转换: IFoo foo = (IFoo)(new Foo()); 。 此转换将始终成功,并且编译器知道存在从FooIFoo可用的隐式转换(引用转换),因此它将为您执行此操作。

  2. 我比编译器更清楚:

     object o = "Hello"; //'compiler knows enough' as all types are derived from object var s = (string)o; 

    在这里,我知道 o实际上是一个字符串,我告诉编译器:即使你认为o是一个对象,相信我,我知道它是一个字符串。

    这也是参考转换。 不会以任何方式触及字符串Hello ,我们唯一要改变的是指向它的引用。

  3. 我知道类型A的给定对象可以转换为类型B的另一个对象,尽管不存在引用转换。

     short s = 1; int i = s; 

    请注意, short 不是 int但恰好是一个知道如何将short转换为int的方法(转换运算符)。 这里我们有一个从shortint的隐式转换。 ii有非常不同的位,但有人实现了必要的逻辑,将一个简短的转换为一个int。

    现在请注意,这是一个隐式转换,你不需要显式地转换短线,尽管没有什么能阻止你做这件事。 它完全有效: int i = (int)s;

     double d = 1.5; int i = (int)d; 

    这里我们有相同类型的演员,但现在它是明确的。 如果您编写int i = d则会出现编译时错误,因为强制转换不是隐式的。

    这提出了一个有趣的观点,你似乎与演员混在一起; 信息丢失。 这是一个很好的做法,隐式强制转换不会丢失信息,而允许显式强制转换。 这似乎是合理的,你不希望编译器在没有告诉你的情况下隐式地丢失丢失信息的东西; 当你将一个short转换为int ,没有任何风险,任何short适合int 。 从doubleint ,显然不是这样,因此转换实现为显式。 (关于已实现的注释,这不是由语言强制执行的,它是编写定义转换运算符的类的人的设计决定)。

一个简单有效的例子可以追溯到旧版本的C#。 List在该版本中不存在,并且为了存储您必须使用非generics集合的数据集合:

 static void Main(string[] args) { ArrayList list = new ArrayList(); list.Add(1); list.Add(2); list.Add(3); int total = 0; foreach(object item in list) total += (int)item; // without casting, compiler never knows item is int Console.WriteLine("Total = {0}", total); } 

另一个有效的例子是事件,大多数事件使用签名(object sender, EventArgs e) 。 为了访问发件人的元素,例如一个按钮,那么你需要强制转换:

 Button btn = (Button)sender; Console.WriteLine(btn.Text); 

在正常转换中使用as运算符来防止空引用exception是一种更好的做法,但上面只是为了提供有效的示例。

只要您想使用该特定类型的对象,就可以转换为特定对象。 另一种转换为另一种类型的方法是

 SomeType x = obj as SomeType; 

当obj为null时,这里不会出现exception。 你应该检查== null。