使用"base"关键字时,基类方法中的代码不执行

Tim*_*rdt 3 c# inheritance rhino-etl

当重写一个抽象方法并尝试调用我目前正在覆盖的基类方法时,我发现了一个非常奇怪的问题.

//In Dll "A"
namespace Rhino.Etl.Core.Operations
{
    using System;
    using System.Collections;
    using System.Collections.Generic;

    public class Row {}

    public interface IOperation
    {
        IEnumerable<Row> Execute(IEnumerable<Row> rows);
    }

    public abstract class AbstractOperation : IOperation
    {
        public abstract IEnumerable<Row> Execute(IEnumerable<Row> rows);
    }

    public abstract class AbstractDatabaseOperation : AbstractOperation
    {
    }

    public abstract class SqlBulkInsertOperation : AbstractDatabaseOperation
    {
        public override IEnumerable<Row> Execute(IEnumerable<Row> rows)
        {
            Console.WriteLine("SqlBulkInsertOperation");
            return rows;
        }
    }
}

//In console app "B"
namespace MyStuff
{
    using System;
    using System.Collections;
    using System.Collections.Generic;

    class Program
    {
        static void Main(string[] args)
        {
            ActualEtlOperation e = new ActualEtlOperation();
            e.Execute(new Row[0]);

            Console.ReadLine();
        }
    }

    public abstract class SqlBulkInsertWithTruncateOperation : SqlBulkInsertOperation
    {
        public override IEnumerable<Row> Execute(IEnumerable<Row> rows)
        {
            Console.WriteLine("Truncate");
            base.Execute(rows);
            return rows;
        }
    }

    public class ActualEtlOperation : SqlBulkInsertWithTruncateOperation
    {

    }
}
Run Code Online (Sandbox Code Playgroud)

基本上,SqlBulkInsertOperation没有做我需要它做的事情,所以我需要在我通过覆盖它来调用Execute(rows)之前和之后做一些工作.但是不执行SqlBulkInsertOperation.Execute(Rows)中的代码.

在Visual Studio中的调试器中运行此代码时,调试器的代码未执行.当我将鼠标悬停在Visual Studio编辑器中的"base"上时,它知道基类的类型为SqlBulkInsertOperation.

我错过了什么?

Jon*_*eet 10

编辑:我发现了这个问题......具有讽刺意味的是,我对Eric的"心灵调试"评论并不是那么遥远,因为这篇博客文章.这是一个简短但完整的程序,将展示正在发生的事情......

using System;
using System.Collections.Generic;

public class Row {}

public abstract class BaseDatabaseOperation
{
    public abstract IEnumerable<Row> Execute(IEnumerable<Row> rows);
}

public abstract class SqlBulkInsertOperation : BaseDatabaseOperation
{
    public override IEnumerable<Row> Execute(IEnumerable<Row> rows)
    {
        Console.WriteLine("In SqlBulkInsertOperation.Execute");
        foreach (var row in rows)
        {
            yield return row;
        }
    }
}

public class MyOverride : SqlBulkInsertOperation
{
    public override IEnumerable<Row> Execute(IEnumerable<Row> rows)
    {
        Console.WriteLine("In MyOverride.Execute");
        return base.Execute(rows);
    }
}

class Test
{
    static void Main()
    {
        BaseDatabaseOperation x = new MyOverride();
        x.Execute(new Row[0]);
    }
}
Run Code Online (Sandbox Code Playgroud)

这将打印"在MyOverride.Execute",但它*不会"打印"在SqlBulkInsertOperation.Execute"...因为该方法是使用迭代器块实现的.

当然,你可以证明这简单多:

using System;
using System.Collections.Generic;

class Test
{
    static IEnumerable<string> Foo()
    {
        Console.WriteLine("I won't get printed");
        yield break;
    }

    static void Main()
    {
        Foo();
    }
}
Run Code Online (Sandbox Code Playgroud)

什么都没有使用方法的返回值 - 它被传递回Main,但没有任何东西调用GetEnumerator()它,然后MoveNext()在结果...所以方法的主体永远不会被执行.

我的迭代块文章,埃里克的博客文章的第二部分,或者从下载第6章中的首页第一的C#版详解(第6章介绍迭代块,并且是免费的)对更多细节.


Eri*_*ert 6

这是我运行的代码:

using System;
using System.Collections.Generic;
public class Row {}
public abstract class BaseDatabaseOperation 
{ 
    public abstract IEnumerable<Row> Execute(IEnumerable<Row> rows); 
} 

public abstract class SqlBulkInsertOperation : BaseDatabaseOperation 
{ 
    public override IEnumerable<Row> Execute(IEnumerable<Row> rows) 
    { 
        Console.WriteLine("base");
        return null;
    } 
} 

public class MyOverride : SqlBulkInsertOperation 
{ 
    public override IEnumerable<Row> Execute(IEnumerable<Row> rows) 
    { 
        Console.WriteLine("override");
        base.Execute(rows);
        return null;
    } 
} 

static class P 
{
    static void Main()
    {
        var m = new MyOverride();
        m.Execute(null);
    }
}
Run Code Online (Sandbox Code Playgroud)

它运行良好; 它产生"覆盖"和"基础".

告诉你什么:修改我在这里发布的程序,以便它产生你遇到的问题,我们将分析它.当您无法真正看到存在问题的真实代码时,很难分析问题.

  • 你的精神调试技能是否有休息日? (3认同)

dth*_*rpe 5

对我来说很好.您的代码需要一点点的清理 - 你确定你编译和执行这段代码,而不是调试代码的早期构建?

class Program
{
    public class Row { }

    public abstract class BaseDatabaseOperation
    {
        public abstract IEnumerable<Row> Execute(IEnumerable<Row> rows);
    }

    public abstract class SqlBulkInsertOperation : BaseDatabaseOperation
    {
        public override IEnumerable<Row> Execute(IEnumerable<Row> rows)
        {
            Console.WriteLine("done");
            return rows;
        }
    }

    public class MyOverride : SqlBulkInsertOperation
    {
        public override IEnumerable<Row> Execute(IEnumerable<Row> rows)
        {
            return base.Execute(rows);
        }
    }

    static void Main(string[] args)
    {
        var x = new MyOverride();
        x.Execute(null);
    }
}
Run Code Online (Sandbox Code Playgroud)