3

抽象メソッドをオーバーライドし、現在オーバーライドしている基本クラスのメソッドを呼び出そうとすると、非常に奇妙な問題が発生します。

//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であることがわかります。

私は何が欠けていますか?

4

5 に答える 5

10

編集:私は問題を見つけました...そして皮肉なことに、このブログ投稿を考えると、エリックへの私の「精神的なデバッグ」コメントはそれほど遠くありませんでした。これは、何が起こっているのかを示す短いが完全なプログラムです...

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

これは「InMyOverride.Execute」を出力しますが、「InSqlBulkInsertOperation.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()結果を呼び出すことはありません。したがって、メソッドの本体が実行されることはありません。

詳細については、イテレータブロックに関する私の記事、Ericのブログ投稿のパート2を参照するか、C#の初版のホームページから第6章をダウンロードしてください(第6章はイテレータブロックについて説明しており、無料です)。

于 2010-09-29T19:59:51.673 に答える
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);
    }
}

正常に動作します。「オーバーライド」と「ベース」を生成します。

教えてください:ここに投稿したプログラムを変更して、発生している問題が発生するようにします。それを分析します。問題を抱えている実際のコードを実際に見ることができない場合、問題を分析することは非常に困難です。

于 2010-09-29T20:02:45.173 に答える
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);
    }
}
于 2010-09-29T20:05:22.963 に答える
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

あなたはあなたの例に含まれていない何か他のことをしたに違いありません。

于 2010-09-29T20:02:35.313 に答える
3

これらはすべて同時にコンパイルされていますか?切断されたミドルベースクラスに苦しんでいる可能性がありますhttp://blogs.msdn.com/b/ericlippert/archive/2010/03/29/putting-a-base-in-the-middle.aspx

于 2010-09-29T20:03:56.297 に答える