C# - 为什么我需要在向下转换之前向上转换为Object?

时间:2012-07-11 18:21:32

标签: c# inheritance casting

在C#中,我处于由环境提供以下类型的场景中:

public interface IFoo {
}

public abstract class Base {
}

public class Derived : Base, IFoo {
}

public class Arbitrary {
    public Base GetBase() { }
}

除此之外,这是我写的。请注意,我可以在代码中保证Arbitrary.GetBase() 总是返回Derived的实例。

public class Arbitrary2 : Arbitrary {
    public IFoo GetDerived() {
        return (IFoo)base.GetBase();
    }
}

但是,此代码失败并显示消息“无法将类型'Base'转换为'IFoo'”。

但是,如果我这样做,那么它可以工作:

public class Arbitrary2 : Arbitrary {
    public IFoo GetDerived() {
        Object baseAsObject = base.GetBase();
        return (IFoo)baseAsObject ;
    }
}

为什么在将它向下传播到IFoo之前​​需要将此向上转换为对象?这两段代码在功能上是相同的,如果转换无效,后者将在运行时可靠地崩溃。我不明白为什么编译器会抱怨。

6 个答案:

答案 0 :(得分:6)

您不需要这样做。您的代码应该按原样运行。有关详细信息,请参阅此计划:

using System;

public interface IFoo { }

public abstract class Base { }

public class Derived : Base, IFoo { }

public class Arbitrary {
    public Base GetBase() { return new Derived(); }
}

public class Arbitrary2 : Arbitrary {
    public IFoo GetDerived() {
        return (IFoo)base.GetBase();
    }
}

class Program
{
    static void Main(string[] args)
    {
        Arbitrary2 test = new Arbitrary2();
        IFoo check = test.GetDerived();

        Console.WriteLine(check.GetType().Name);

        Console.WriteLine("Press key to exit:");
        Console.ReadKey();
    }
}

答案 1 :(得分:1)

你的GetBase()方法返回Base,它没有实现IFoo。

答案 2 :(得分:1)

Base无法转换为IFoo,因为BaseIFoo没有任何关系:

public abstract class Base { }

根据此声明,很可能Base的实例不属于IFoo类型。实际上,基于此声明,编译器完全没有理由假设任何给定的Base实例都会实现IFoo

Derived 实施IFoo

public class Derived : Base, IFoo { }

但你没有返回Derived,而是返回Base。通过Object对其进行多态化,您实际上是在“欺骗”编译器。你告诉它你知道的比它更多,它应该听你的。这可以很好,只要你实际上比编译器知道更多。而你知道编译器不知道的是Base的每个实例都能够变形为IFoo

在这种情况下,为什么不在IFoo上实施Base?这样你就可以与编译器分享你的知识,每个人都会很高兴。

答案 3 :(得分:1)

编译器禁止显式强制转换的原因是Base未实现IFoo

如果您保证 GetBase()将始终返回Derived,那么您只需在Derived之前插入一个强制转换为IFoo施放:

public class Arbitrary2 : Arbitrary {
    public IFoo GetDerived() {
        return (IFoo)(Derived)base.GetBase();
    }
}

当然,如果你弄错的话,这会在运行时抛出。或者,如果失败,您可以使用as强制转换只返回null

public class Arbitrary2 : Arbitrary {
    public IFoo GetDerived() {
        return base.GetBase() as IFoo;
    }
}

答案 4 :(得分:1)

Arbitrary.GetBase()返回Base的实例。 Base的层次结构不包含IFoo.

在运行时,是的,您的对象是Derived实例,但基于编译器知道的内容 - 类关系 - 没有连接,因此可以从{{1}进行强制转换当你尝试第一种方法时,{} Base

答案 5 :(得分:1)

你不能只写

public class Arbitrary2 : Arbitrary {
    public IFoo GetDerived() {
        return (Derived)this.GetBase();
    }
}

编译器将看到DerivedBase之间的连接,因此显式转换为Derived应该没问题。那么任何Derived肯定是IFoo,所以不需要再投入额外的时间(转换是隐含的)。

请勿使用base.关键字。可以说this.(如上所述)或遗漏。

编辑:此外,您的原始代码已经编译,但我的版本可能更容易阅读。