在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之前需要将此向上转换为对象?这两段代码在功能上是相同的,如果转换无效,后者将在运行时可靠地崩溃。我不明白为什么编译器会抱怨。
答案 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
,因为Base
与IFoo
没有任何关系:
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();
}
}
编译器将看到Derived
和Base
之间的连接,因此显式转换为Derived
应该没问题。那么任何Derived
肯定是IFoo
,所以不需要再投入额外的时间(转换是隐含的)。
请勿使用base.
关键字。可以说this.
(如上所述)或遗漏。
编辑:此外,您的原始代码已经编译,但我的版本可能更容易阅读。