为什么我无法从Derived访问M3方法? Intellisense仅显示基类中的M1和M2。 如何将bc的参考值从Base类型更改为Refernce Type, 这样我就可以访问M3方法。
class Program
{
static void Main(string[] args)
{
Base bc = new Derived();
bc.M3():// error
}
}
class Base
{
public void M1()
{
Console.WriteLine("M1 from BASE.");
}
public void M2()
{
Console.WriteLine("M2 from BASE.");
}
}
class Derived : Base
{
public void M3()
{
Console.WriteLine("M3 from DERIVED.");
}
}
答案 0 :(得分:6)
编译器必须在编译时解析名称M3
。这是在Base
类型的引用上调用的,Base
没有该名称的成员。它碰巧在运行时指向Derived
的实例这一事实在这里没有任何意义,因为编译器正在查看编译时可用的信息。
是的,在这种特定情况下,编译器可以看到bc
始终初始化为Derived
值,因此它应该在那里看。然而,这不是c#编译器的工作原理。它只查看所涉及引用的编译时类型
答案 1 :(得分:1)
因为您将您的类型转换为基类,所以所有可用成员的集合将减少为Base
中可用的成员集。
Derived bc = new Derived();
bc.M3():// CORRECT
或只是
var bc = new Derived();
bc.M3():// CORRECT
如果您需要在应用中使用Base
类进行多态,并且需要使用M3()
,请考虑将其移至Base
类
答案 2 :(得分:1)
因为bc
引用带来的唯一保证是它会引用Base
的实例或从Base
派生的内容。
考虑代码是否改变如下:
Base bc = new Derived();
if(DateTime.DayOfWeek == DayOfWeek.Sunday)
{
bc = new Base();
}
bc.M3();
这是完全合法的,因为bc
的保证仍然完整。
有两种方法可以解决这个问题:Casting和polymorphism。
转换意味着您告诉编译器您知道这确实是Derived
实例,即使引用属于Base
类型。
Base bc = new Derived();
if(bc is Derived)
{
((Derived)bc).M3();
}
另一种是在基类中声明M3函数,然后在派生类
中覆盖它class Base
{
// Other stuff...
public virtual void M3()
{
}
}
class Derived : Base
{
public override void M3()
{
Console.WriteLine("M3 from DERIVED.");
}
}
答案 3 :(得分:1)
正如其他人所说,bc
被声明为Base
类型。你需要先施展它
Base bc = new Derived();
((Derived)bc).M3()
如果bc
实际上是Base
类型而不是Derived
,则会出现运行时错误。
答案 4 :(得分:1)
这是因为编译器只看到您正在使用Base类型的变量。
请使用以下代码:
Base bc = null;
if (SomeValue)
{
bc = new Base();
}
else
{
bc = new Derived();
}
SomeValue的值在运行时可能会有所不同。这意味着编译器在编译时不会知道bc
的实际类型。这是基类的全部概念。您与基类共享相同的接口,但您可以更改方法的实现。
但是,您可以将类型转换为其他类型:
Derived dc = bc as Derived;
if ( dc != null ) // cast succeeded so we have a Derived
{
dc.M3();
}
要仅检查某个类型是否属于其他类型,您可以使用is
:if (dc is Derived)
。
请注意这样做的危险。这样,您就会使用所有类型特定的检查来乱丢代码,这使得它更难理解和维护。如果您想了解更多有关此内容的信息,请阅读S OLID patterns。