什么是对象铸造?
我对于什么是对象转换以及它的用途有点困惑。 我已阅读关于Casting and type conversion的MSDN文档,我可以看到为了进行显式转换,您需要使用一个演员操作符。我理解文档中给出的示例,如果在将一种类型转换为另一种类型时可能会丢失一些数据,则需要使用转换运算符。什么是对象铸造?
我只是对如何投射物体感到困惑?我假设对象是一个类的实例,可能容纳更多的信息,而不仅仅是一个简单的数据类型?那么,如何,为什么以及何时需要投射物体?
我见过铸造一个对象,这是一个简单的例子:
SomeType name = (SomeType)obj;
我缺少的东西,或者是这个对象铸造?如果是这样,你需要在什么情况下投出这样的对象?
您只需要使用铸造操作员,当没有隐式铸造可用,编译器可以验证是安全的。如果有一个,编译器确定演员会成功,那么它会自动为你做。
现在,为什么我应该使用演员?
- 有
A
类型的对象,你需要B
类型和 的对象是有办法的A
转换成B
:当您或者您应该使用一个演员。 - 你有
A
类型的一个对象的引用,你需要一个 参考B
类型到同一个对象,都A
和B
是有效的引用类型到该对象。
另一种方式来思考是:
- 当你知道的比编译器更好,你知道一个对象是 类型编译器不能。
- 当一个对象不是某种类型,但你知道有一个有效的转换为该类型。
这带来了一种分组蒙上基于什么剧组真的是这样做的:
- 投保了保留身份。
- 没有的演员。
第一组是我们所说的参考转换。它们根本不改变对象,它们只是改变指向对象的引用的类型(显然,它们只适用于引用类型,值类型不能引用转换,因为你无法获得对值的引用类型)。请注意,这种类型的转换是由语言本身提供的,不能通过实现参考转换。
第二组是所有需要在对象中发生表示变化的转换,也就是说,由转换返回的对象的位与被转换对象的位不同。这些类型的类型是您可以在任何C#类/结构中实现的implicit
和explicit
运算符。
您可以阅读更多关于此in this SO answer。
好吧,这很有趣,但你能给我具体的例子吗?是的,当然:
-
编译器知道就够了:
interface IFoo { } class Foo: Foo { } IFoo foo = new Foo();
有来自
Foo
隐式转换到IFoo
在最后声明:IFoo foo = (Foo)(new Foo());
。这个演员阵容将成功总是和编译器知道有一个从Foo
到IFoo
隐式投射(参考转换),所以它会为你做。 -
我知道优于编译器:
object o = "Hello"; var s = (string)o;
在这里,我知道
o
真的是一个字符串,我告诉编译器:即使你认为o
是一个对象,相信我,我知道它的一个字符串。这也是一个参考转换。字符串
Hello
没有以任何方式触及,我们正在改变的唯一的事情就是指向它的参考。 -
我知道类型A的给定对象可转换为B类型的另一个对象,尽管不存在引用转换。
short s = 1; int i = s;
注意,一个
short
不是的int
但恰好是一个方法(转换运算符),其知道如何将short
转换为int
。这里我们有一个从short
到int
的隐式转换。s
和i
有很不同的位,但有人实现了将短变成int的必要逻辑。现在请注意,这是一个隐式转换,您不需要明确地转换短暂的转换,尽管没有任何东西阻止您这样做。它完全有效:
int i = (int)s;
。double d = 1.5; int i = (int)d;
在这里,我们有相同类型的演员,但现在它明确。如果你会写
int i = d
,你会得到一个编译时错误,因为这个转换不是隐式的。这提出了一个有趣的观点,你似乎在与演员混为一谈;信息丢失。隐式强制转换不会丢失信息,但允许显式强制转换。这似乎是合理的,你不希望编译器在没有告诉你的情况下隐含地丢失信息;当您将
short
投射到int
时,没有风险,任何short
都适合于int
。当从double
投射到int
时,这显然不是真实的,因此该投射被实施为显式。 (关于的注意事项实现了,这不是由语言强制执行的,它是编写定义演员操作员的类的人的设计决定)。
只要您想使用该特定类型的对象,就会投射到特定对象。 投放到另一种类型的另一种方式是
SomeType x = obj as SomeType;
在这里,你不会得到一个异常时,obj为null。虽然你应该检查== null。
一个简单有效的例子可以追溯到旧版本的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
运营商在正常铸造防止空引用异常,但以上只是提供有效的例子。
拆箱是一种情况..我们不得不在c#中引入泛型方法之前进行过多的铸造。这是因为太多的方法使用'object'参数,比如非通用版本'List'。想想发件人如果输入'object'并且你需要将它转换为'Button'的事件。确定'as'运营商是首选,但我只是想解释一个有效的案例。 – user3185569