在覆盖抽象方法并尝试调用我目前正在覆盖的基类方法时,我发现了一个非常奇怪的问题。
//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。
我错过了什么?
答案 0 :(得分: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]);
}
}
那将打印“在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 blocks,part 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