Base to Derived是可能的(Boxing),但Derived to base给出了运行时异常,但这相当于Unboxing

时间:2013-11-21 09:09:02

标签: c#

基础到衍生是可能的(拳击)。 但Derived to base会给出运行时异常,但这相当于Unboxing。 为什么会如此

Base b = new Base();
Child c = new Child();
c = (child)b; // No compilation error but run time error

object a;
int i = (int)a; //No error Unboxing 

是否可能因为对象是顶级类的所有值类型或Object类继承的Ref类型。  public int ConvertToINT(object obj)         {             int i =(int)obj;             return Convert.ToInt32(obj);         }

4 个答案:

答案 0 :(得分:1)

来自msdn Boxing and Unboxing

  

Boxing是将值类型转换为类型对象或由此值类型实现的任何接口类型的过程。

你的样本中的

Base b = new Base();
Child c = new Child();
c = (Child)b; // No compilation error but run time error

你创建两个不同的对象并尝试强制转换它,这与

不同
Base b = new Child();
Child c = new Child();
c = (Child)b; // No compilation error, no run time error if Child derived from Base

答案 1 :(得分:1)

您正在使用参考投射混淆价值拳击。

如果你这样做:

int x = 1;
object a = x;
int i = (int) a;

然后行object a = x;通过(有效地)创建包含整数值1的包装类来装箱x的整数值。

当您通过将其转换回int来取消装箱时,运行时代码会检查其基础类型是否正确(int,因为您要转换为int),然后它提取基础值并将其分配给目标int变量。

如果你这样做:

public class BaseClass
{
}

public class DerivedClass: BaseClass
{
    public int Value;
}

...

BaseClass b = new BaseClass();
DerivedClass d = (DerivedClass) b;
int myValue = d.Value; // What would happen? BaseClass doesn't have a Value property!

这里没有涉及拳击,因为我们正在使用引用类型。相反,此代码试图将基类视为派生类。

这显然是不可能的,因为例如,如果您尝试访问DerivedClass.Value会发生什么?该属性在基类中不存在,因此不可能将基类的实例视为派生类。

答案 2 :(得分:1)

我可能会因此而被投票;但有一种方法调情处理更高的派生对象;如果这是你想要完成的。 这不是上传;这是 Contravarience ;只要您不需要随时返回T值,就可以调用更高的派生接口对象。

internal interface IVet<in T> where T : Animal
{
    void Set(T animal);
    void Heal();
}

class Animal
{
    public virtual void Examine(){Console.WriteLine("Animal");}
}

class Cat : Animal
{
    public override void Examine(){Console.WriteLine("Cat");}
}

internal class Vet<T> : IVet<T> where T : Animal
{
    private T _value;

    public void Set(T animal)
    {
        _value = animal;
    }

    public void Heal()
    {
        _value.Examine();
    }
}

所以你可以做这样的事情

internal class Program
{
    private static void Main(string[] args)
    {
        IVet<Animal> _vetAnimal = new Vet<Animal>();
        IVet<Cat> _vetCat = _vetAnimal;

        _vetCat.Set(new Cat());
        _vetCat.Heal();
    }
}

注意我们有一个Vet<Animal>对象,我们将它分配给逆变器接口IVet<Cat>。然后我们可以使用此接口传递'Cat'变量并对其执行某些操作。所以逆变让你可以从IVet<Animal>IVet<Cat>进行演员表演。

在某些情况下有用;但同样,不是向上转换值......基本上是一个包装器,您可以在其中提升接口的泛型类型。

答案 3 :(得分:0)

你误解了一些OOP概念。虽然在需要基类时可以使用派生类,但是你不能采用其他方式。

这些工作:

Base b1 = new Base();
Base b2 = new Child();
Base b3 = (Base)b2;

有效,因为Base根本不是Child

Base b1 = new Base();
Child c1 = (Child)b1;

在众所周知的Vehicle例子中发言:

虽然卡车仍然是车辆(每Child也是Base),但并非每辆车都是卡车(并非每个Base都是Child