Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/288.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/batch-file/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从基调用虚拟方法_C#_Virtual Functions - Fatal编程技术网

C# 从基调用虚拟方法

C# 从基调用虚拟方法,c#,virtual-functions,C#,Virtual Functions,我正在尝试为基于的MigraDoc创建一个库,它支持不同类型的文档。我的想法是创建一个基类,为CreatePage()(负责页面布局的方法)创建一个虚拟方法。但是,概念是应该从用户调用的名为CreateDocument()的方法调用CreatePage()。遗憾的是,可以重写CreatePage(),但并不意味着直接调用它。它看起来像这样: public class DocumentWriter { private Document document; public virtu

我正在尝试为基于的MigraDoc创建一个库,它支持不同类型的文档。我的想法是创建一个基类,为
CreatePage()
(负责页面布局的方法)创建一个虚拟方法。但是,概念是应该从用户调用的名为
CreateDocument()
的方法调用
CreatePage()
。遗憾的是,可以重写
CreatePage()
,但并不意味着直接调用它。它看起来像这样:

public class DocumentWriter
{
    private Document document;

    public virtual void CreateDocument(IDocumentArgs args)
    {
       document = new Document();

       DefineStyles();
       CreatePage();
       FillContent(args);
    }

    public virtual void CreatePage()
    {
        // Create page layout here
    }

    // Remaining code skipped for readability...
}
但是如果创建继承的类,它重写
CreatePage()
,那么将从
CreateDocument()
调用哪个方法

  • 原始虚拟(非重写)方法
  • 重写
    CreatePage()的方法

由于该方法是虚拟的,因此将调用正确的版本。工作的机制称为

事实上,
CreateDocument
甚至不需要是虚拟的就可以工作(除非您打算在另一个基类中重写它)

您可以在使用时看到它(注意,我将
CreatePage
设置为受保护的
,因此不能从
DocumentWriter
或其基类外部调用它)。请注意,即使我通过基类类型显式调用
CreateDocument
,它也会根据对象的运行时类型调用正确的版本

public class DocumentWriter
{
    public /*virtual*/ void CreateDocument()
    {
       CreatePage();
    }

    protected virtual void CreatePage()
    {
        System.Console.WriteLine("DocumentWriter.CreatePage()");
    }
}

public class PdfDocumentWriter : DocumentWriter
{
    protected override void CreatePage()
    {
        System.Console.WriteLine("PdfDocumentWriter.CreatePage()");
    }
}

public class HtmlDocumentWriter : DocumentWriter
{
    protected override void CreatePage()
    {
        System.Console.WriteLine("HtmlDocumentWriter.CreatePage()");
    }
}

public static class Program
{
    public static void Main()
    {
        DocumentWriter documentWriter = new PdfDocumentWriter();
        documentWriter.CreateDocument();

        // Re-use the same variable. 
        // CreateDocumentwill still call the correct version of CreatePage.
        documentWriter = new HtmlDocumentWriter();
        documentWriter.CreateDocument();
    }
}
这张照片

PdfDocumentWriter.CreatePage()
HtmlDocumentWriter.CreatePage()

正如预期的那样。

将调用覆盖。如果您随后创建派生类的实例并调用CreateDocument,则仅当您不打算直接从另一个代码调用
CreatePage()
时,它才会调用覆盖的方法。您可以使用
受保护的
修改器这就是
ovderride
的要点,能够覆盖基本实现。Aynway您可以自己尝试一下,编写一个带有虚拟成员的测试程序,并在您的类中重写它时检查调用了哪个成员。对于这种方法,请使用模板设计模式和抽象类,其中方法将保持抽象。谢谢您提供了非常易懂的答案。我将使基函数成为非虚拟函数(因为这不应该被重写),并且只允许重写子方法。