【问题标题】:What is object casting?什么是对象转换?
【发布时间】:2017-01-22 17:45:17
【问题描述】:

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

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

我看过一个投射对象的例子,很简单:

SomeType name = (SomeType)obj;

是我遗漏了什么,还是这个对象正在投射?如果是,在什么情况下需要像这样投射对象?

【问题讨论】:

  • 拆箱是一种情况。在c#中引入泛型方法之前,我们不得不做太多的转换。这是因为太多方法使用了object 参数,例如非泛型版本List。考虑一下发送者如果类型为object 的事件,您需要将其转换为Button 例如。当然as 运算符是首选,但我只是想解释一个有效的案例。

标签: c# object casting


【解决方案1】:

只有在编译器可以验证安全的隐式强制转换不可用时,才需要使用强制转换运算符。如果有一个并且编译器确定强制转换会成功,那么它将自动为您完成。

现在,我为什么要使用演员表?您应该在以下情况下使用演员表:

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

另一种思考方式是:

  • 当您比编译器更了解并且您知道对象是 类型编译器不能。
  • 当对象不属于特定类型但您知道存在到该类型的有效转换时。

这带来了一种根据演员的实际行为对演员进行分组的方法:

  • 保留身份的演员表。
  • 强制转换。

第一组是我们所说的参考转化。这些根本不会改变对象,它们只是改变了指向对象的引用的类型(显然,它们只适用于引用类型,值类型不能进行引用转换,因为你无法获得对值的引用类型)。请注意,这种类型的转换是由语言本身提供的,您无法实现引用转换。

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

您可以阅读有关此in this SO answer 的更多信息。

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

  1. 编译器知道的够多了:

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

    在最后一条语句中存在从Foo 到IFoo 的隐式转换:IFoo foo = (IFoo)(new Foo());。这个转换将成功总是并且编译器知道有一个从Foo到IFoo的隐式转换(引用转换)可用,所以它会为你做.

  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。这里我们有一个从short 到int 的隐式转换。 s 和 i 有非常不同的位,但有人实现了将 short 转换为 int 的必要逻辑。

    现在请注意,这是一个隐式转换,您不需要显式转换 short,尽管没有什么能阻止您这样做。这样做完全有效:int i = (int)s;.

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

    这里我们有相同类型的演员表,但现在它是显式的。如果你写了int i = d,你会得到一个编译时错误,因为转换不是隐式的。

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

【讨论】:

    【解决方案2】:

    一个简单有效的示例可以追溯到旧版本的 C#。 List<T> 在那个版本中不存在,为了存储数据集合,您必须使用非泛型集合:

    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 运算符而不是正常转换来防止空引用异常,但以上只是提供有效示例。

    【讨论】:

      【解决方案3】:

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

      SomeType x = obj as SomeType;
      

      这里当 obj 为 null 时不会出现异常。不过,您应该检查一下 == null。

      【讨论】:

        猜你喜欢
        • 2016-11-04
        • 2015-01-09
        • 1970-01-01
        • 2020-04-23
        • 1970-01-01
        • 1970-01-01
        • 2013-09-04
        • 1970-01-01
        • 2014-04-04
        相关资源
        最近更新 更多