Pergunta

Estou vendo um problema muito estranho ao substituir um método abstrato e tentar chamar o método da classe base que estou substituindo atualmente.

//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
    {

    }
}

Basicamente, o SQLbulkinsertoPoperation não faz o que eu preciso fazer, então preciso fazer um pouco de trabalho antes e depois de ligar para executar (linhas) nele, substituindo -o. Mas o código em sqlbulkinsertoperation.execute (linhas) não é executado.

Ao executar esse código no depurador no Visual Studio, o depurador, o código não foi executado. Quando o mouse o mouse sobre a "base" no editor do Visual Studio, sabe que a classe base é do tipo sqlbulkinsertoiner.

o que estou perdendo?

Foi útil?

Solução

EDIT: Eu encontrei o problema ... e ironicamente, meu comentário "psíquico de depuração" para Eric não estava tão longe, dado esta postagem do blog. Aqui está um programa curto, mas completo, que demonstrará o que está acontecendo ...

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

Isso imprimirá "no myoverride.execute", mas *não "imprimirá" em sqlbulkinsertoperation.execute "... porque esse método é implementado com um bloco de iterador.

Claro, você pode demonstrar isso Muito de mais simplesmente:

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

Nada está usando o valor de retorno do método - ele está sendo transmitido para Main, mas nada nunca liga GetEnumerator() nele, e então MoveNext() no resultado ... para que o corpo do método nunca seja executado.

Ver Meu artigo sobre blocos de iterador, Parte dois da postagem do blog de Eric, ou baixar o capítulo 6 do página inicial do primeiro Edição de C# em profundidade (O capítulo 6 abrange blocos de iterador e é gratuito) para obter mais detalhes sobre isso.

Outras dicas

Aqui está o código que eu corri:

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

Funciona bem; Produz "substituição" e "base".

É o seguinte: Modifique o programa que publiquei aqui para que produz o problema que você está enfrentando, e analisaremos isso. É muito difícil analisar um problema quando você não pode realmente ver o código real que está tendo problemas.

Funciona bem para mim. Seu código precisa de um pouco de limpeza - você tem certeza de que está compilando e executando esse código, e não depurar uma compilação mais antiga do seu código?

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

Seu exemplo não compila, alguns retornos estão faltando, mas o seguinte exemplo modificado

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

Chamado assim:

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

gera a saída

do own work here
does useful work

Você deve ter feito outra coisa não incluída no seu exemplo.

Todos estão sendo compilados ao mesmo tempo? Você pode estar sofrendo com a classe Base Média Desconectada http://blogs.msdn.com/b/ericlippert/archive/2010/03/29/putting-base-in-the-middle.aspx

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top