Код в методе базового класса не выполняется при использовании ключевого слова «base» - PullRequest
3 голосов
/ 29 сентября 2010

Я вижу очень странную проблему при переопределении абстрактного метода и попытке вызвать метод базового класса, который я сейчас переопределяю.

//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 (строки), переопределив его. Но код в SqlBulkInsertOperation.Execute (Rows) не выполняется.

При запуске этого кода в отладчике в Visual Studio код отладчика не выполняется. Когда я наведите курсор мыши на «base» в редакторе Visual Studio, он узнает, что базовый класс имеет тип SqlBulkInsertOperation.

Чего мне не хватает?

Ответы [ 5 ]

10 голосов
/ 29 сентября 2010

РЕДАКТИРОВАТЬ: Я нашел проблему ... и по иронии судьбы, мой комментарий "Эрик отладки" для Эрика был не так уж далек, учитывая этот пост в блоге . Вот короткая, но полная программа, которая продемонстрирует, что происходит ...

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

Это будет печатать «In 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() для результата ... так что тело метода никогда не выполняется.

См. мою статью о блоках итераторов , часть вторая в блоге Эрика , или загрузите главу 6 с домашней страницы первого издания C # in Depth (глава 6 посвящена блокам итераторов и бесплатна) для более подробной информации по этому вопросу.

6 голосов
/ 30 сентября 2010

Вот код, который я запустил:

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

Работает нормально; он производит "override" и "base".

Скажите, что: измените программу, которую я выложил здесь, чтобы она выявила проблему, с которой вы столкнулись, и мы проанализируем ее Очень трудно проанализировать проблему, когда вы на самом деле не можете увидеть реальный код, который имеет проблемы.

5 голосов
/ 30 сентября 2010

Работает нормально для меня. Ваш код требует небольшой очистки - вы уверены, что компилируете и выполняете этот код, а не отлаживаете старую сборку кода?

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 голосов
/ 30 сентября 2010

это все компилируется одновременно?вы можете страдать от отключенного среднего базового класса http://blogs.msdn.com/b/ericlippert/archive/2010/03/29/putting-a-base-in-the-middle.aspx

3 голосов
/ 30 сентября 2010

Ваш пример не компилируется, некоторые результаты отсутствуют, но следующий модифицированный пример

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

Вы, должно быть, сделали что-то еще, не включенное в ваш пример.

...