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

时间:2010-09-29 19:54:14

标签: 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
    {

    }
}

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

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

我错过了什么?

5 个答案:

答案 0 :(得分:10)

编辑:我发现了这个问题......具有讽刺意味的是,我对埃里克的“心理调试”评论并没有那么遥远,给出this blog post。这是一个简短但完整的程序,它将展示正在发生的事情......

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]);
    }
}

那将打印“在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();
    }
}

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

请参阅my article on iterator blockspart two of Eric's blog post或从home page of the first edition of C# in Depth下载第6章(第6章介绍迭代器块,并且是免费的),以获取更多详细信息。

答案 1 :(得分: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);
    }
}

运行良好;它产生“覆盖”和“基础”。

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

答案 2 :(得分: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);
    }
}

答案 3 :(得分:3)

您的示例未编译,缺少某些返回,但以下修改示例

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("does useful work");
        return new Row[0];
    }
}

public class MyOverride : SqlBulkInsertOperation
{
    public override IEnumerable<Row> Execute(IEnumerable<Row> rows)
{

        Console.WriteLine("do own work here");

    //This does not execute code in base class!
        base.Execute(rows);

        return new Row[0];
}
}

这样称呼:

MyOverride mo = new MyOverride();
mo.Execute(new Row[0]);

生成输出

do own work here
does useful work

您必须完成其他未包含在您的示例中的内容。

答案 4 :(得分:3)

这些都是同时编译的吗?您可能会遇到断开连接的中间基类http://blogs.msdn.com/b/ericlippert/archive/2010/03/29/putting-a-base-in-the-middle.aspx