2017-01-22 162 views
1

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

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

我见过铸造一个对象,这是一个简单的例子:

SomeType name = (SomeType)obj; 

我缺少的东西,或者是这个对象铸造?如果是这样,你需要在什么情况下投出这样的对象?

+0

拆箱是一种情况..我们不得不在c#中引入泛型方法之前进行过多的铸造。这是因为太多的方法使用'object'参数,比如非通用版本'List'。想想发件人如果输入'object'并且你需要将它转换为'Button'的事件。确定'as'运营商是首选,但我只是想解释一个有效的案例。 – user3185569

回答

2

您只需要使用铸造操作员,当没有隐式铸造可用,编译器可以验证是安全的。如果有一个,编译器确定演员会成功,那么它会自动为你做。

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

  • A类型的对象,你需要B类型和 的对象是有办法的A转换成B:当您或者您应该使用一个演员。
  • 你有A类型的一个对象的引用,你需要一个 参考B类型到同一个对象,都AB是有效的引用类型到该对象。

另一种方式来思考是:

  • 当你知道的比编译器更好,你知道一个对象是 类型编译器不能。
  • 当一个对象不是某种类型,但你知道有一个有效的转换为该类型。

这带来了一种分组蒙上基于什么剧组真的是这样做的:

  • 投保了保留身份。
  • 没有的演员。

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

第二组是所有需要在对象中发生表示变化的转换,也就是说,由转换返回的对象的位与被转换对象的位不同。这些类型的类型是您可以在任何C#类/结构中实现的implicitexplicit运算符。

您可以阅读更多关于此in this SO answer

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

  1. 编译器知道就够了:

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

    有来自Foo隐式转换到IFoo在最后声明:IFoo foo = (Foo)(new Foo());。这个演员阵容将成功总是和编译器知道有一个从FooIFoo隐式投射(参考转换),所以它会为你做。

  2. 我知道优于编译器:

    object o = "Hello"; 
    var s = (string)o; 
    

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

    这也是一个参考转换。字符串Hello没有以任何方式触及,我们正在改变的唯一的事情就是指向它的参考。

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

    short s = 1; 
    int i = s; 
    

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

    现在请注意,这是一个隐式转换,您不需要明确地转换短暂的转换,尽管没有任何东西阻止您这样做。它完全有效:int i = (int)s;

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

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

    这提出了一个有趣的观点,你似乎在与演员混为一谈;信息丢失。隐式强制转换不会丢失信息,但允许显式强制转换。这似乎是合理的,你不希望编译器在没有告诉你的情况下隐含地丢失信息;当您将short投射到int时,没有风险,任何short都适合于int。当从double投射到int时,这显然不是真实的,因此该投射被实施为显式。 (关于的注意事项实现了,这不是由语言强制执行的,它是编写定义演员操作员的类的人的设计决定)。

0

只要您想使用该特定类型的对象,就会投射到特定对象。 投放到另一种类型的另一种方式是

SomeType x = obj as SomeType; 

在这里,你不会得到一个异常时,obj为null。虽然你应该检查== null。

1

一个简单有效的例子可以追溯到旧版本的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运营商在正常铸造防止空引用异常,但以上只是提供有效的例子。