C#-在构造函数或析构函数中调用的虚拟函数的行为

我已经阅读了一些有关虚拟函数在c和c#之间的构造函数或析构函数中调用的不同行为的材料.然后,我测试以下代码,以确认c#可以调用虚拟派生的虚拟函数,因为其对象存在于构造函数之前.但是我发现结果与c中的类似代码相同.谁能告诉我为什么C#不能显示“ 22”而只能显示“ 12”的原因.

C#代码

public class Base
{
    public Base() { fun(); }
    public virtual void fun() { Console.WriteLine(1); }
}
public class Derived : Base
{
    public Derived() { fun(); }
    public virtual void fun() { Console.WriteLine(2); }
}

C代码

class Base
{
public:
    Base(){fun();}
    virtual void fun(){cout<<1;}
};
class Derived : Base
{
public:
    Derived(){fun();}
    virtual void fun(){cout<<2;}
};

c和C#的输出结果均为“ 12”.

解决方法:

您的C#代码中有错误.

要覆盖C#函数,您必须指定override关键字.
如果您再次编写virtual,则会使基本功能蒙上阴影,但是如果没有new关键字,您应该得到警告.

如果两个都声明为虚拟,则两个函数的名称相同!

让我们举个例子…

public class Base
{
    public Base() { fun(); }
    public virtual void fun() { Console.Write(1); }
}

public class Derived : Base
{
    public Derived() { fun(); }
    public override void fun() { Console.Write(2); }
}

public class DerivedWithError : Base
{
    public DerivedWithError() { fun(); }
    public new virtual void fun() { Console.Write(3); }
}

...

// This will print "22".
Base normal = new Derived();
Console.WriteLine();

// This will print "13" !!!
Base withError = new DerivedWithError ();
Console.WriteLine();

// Let's call the methods and see what happens!

// This will print "2"
normal.fun();
Console.WriteLine();

// This will print "1" !!!
withError.fun();
Console.WriteLine(); 

阴影表示“添加相同名称的新方法而不使用多态性”.
如果没有override关键字,您将禁用多态性.

因此,现在一切都应该干净并且易于理解.

DerivedWithError.fun()是一个全新的虚拟方法.它与基类中的fun函数具有相同的名称,但它们没有关联!

从虚拟表(或虚拟方法表,如果您更喜欢使用其他名称)的角度来讲,基本函数和派生函数的阴影会遮盖虚拟表中的两个不同条目,即使它们具有相同的名称也是如此.
如果改用override,则将强制派生类中的func方法覆盖Base.func占用的虚拟表项,这是多态性.

危险,但.NET允许,请务必谨慎使用语法!

您可以在C#中的构造函数中调用虚拟函数,但是通常在派生类中,如果在基本构造函数中调用了方法,则在使用派生类中的字段时应格外小心.
现在,为了简洁起见,避免混乱和风险,您应该避免在构造函数中调用虚拟方法,但实际上,多次使用是非常有用的.

例如,所谓的“工厂方法”不能访问任何变量.

public abstract class MyClass
{
    public IList<string> MyList { get; private set; }

    public MyClass()
    {
         this.MyList = this.CreateMyList();
    }

    protected abstract IList<string> CreateMyList();
}

public class MyDerived : MyClass
{
    protected override IList<string> CreateMyList()
    {
        return new ObservableCollection<string>();
    }
}

这是完全合法的,并且有效!

上一篇:Item 4: Enforce noninstantiability with a private constructor.


下一篇:No constructor found in domain