考虑这种情况:
// This decides what derived class to return depending on parameters you pass in
FunkyBase funky = FunkyFactory.Create("A");
如果编译器做了一些分析,以确定funky
总是FunkyDerivedA
的基础上你传递,随后的两段代码是紧密耦合。此代码是说:“我知道这是FunkyBase
或从中派生出来的东西,但这就是我所知道的,所以不要给我任何不在该基类上的选项。如果Visual Studio和.NET编译器帮忙,给你所有的方法和属性FunkyDerivedA
,那么你可以这样做:
public class FunkyDerivedA : FunkyBase
{
public SomeProperty { get; set; }
}
///// SNIP /////
FunkyBase funky = FunkyFactory.Create("A");
funky.SomeProperty = 7;
然后一切正常,因为这是你正在使用的实际对象。但是,然后一个美好的一天有所改变,你想切换到FunkyDerivedB
,忘记该属性不存在于该类。
public class FunkyDerivedA : FunkyBase
{
public SomeProperty { get; set; }
}
// notice it doesn't have the same property
public class FunkyDerivedB : FunkyBase
{
}
///// SNIP /////
// Danger, Will Robinson!
FunkyBase funky = FunkyFactory.Create("B");
funky.SomeProperty = 7;
在这一点上,事情可能会以非常不明显的方式失败。投射是你的信号,你知道你在做什么。这是对您或任何维护您的代码的人的提醒,即您正在对您获得的对象的类型(在本例中为工厂方法)做出假设,并且在更改此代码时应小心谨慎。
现在,这并不意味着C#不能做你在问什么。它可以在一定程度上。
从.NET 3.0中,var
关键字(见the MSDN article)让你放弃声明类型:
var funky = new FunkyDerivedA();
智能感知和编译时类型检查的工作,它只是计算出的类型是什么基于方法的返回类型。请注意,在我上面的工厂示例中,如果Create
方法刚刚返回基类,那么这将是该类型。它不会根据对调用树的分析或类似的东西将它转换为更派生的类。
从.NET v4.0开始,您可以使用dynamic
(请参阅the MSDN article)关键字,该关键字放弃编译时类型检查,以便让您按照自己的意愿进行操作。当然,如果你弄错了,你会得到一个运行时异常(不是编译时错误),因为它在运行时解决,而不是编译时。同样,Intellisense也不起作用,所以要确保您知道对象是什么以及可用的成员。
另请注意,与铸造一样,dynamic
关键字也是一个信号,表示您知道自己在做什么,并对任何不正确的事情承担责任。
希望帮助
按照从@DaveShaw保留关键字的响应为C#http://msdn.microsoft.com/en-us/library/x53a06bb.aspx – Lloyd
是的,可以。您可以使用派生类的类型的变量。 – millimoose
您要求的内容需要进行某种数据流分析,以将强制类型转换为编译器可以确定的内容,即分配给变量的当前值,并使语言更加复杂。这听起来像是当语言设计者只需在'if'块中拥有派生类型的局部变量时就不会去的努力。 – millimoose