我可以用另一个具有相同名称和签名的C#方法替换它吗?

时间:2013-01-09 06:26:38

标签: c# .net

我有以下情况。一些.Net运行时方法不能很好地工作,我需要制定一个解决方法。就像有SqlCommand.ExecuteReader()有时会返回一个封闭的读者对象,我希望有这样的代码:

 SqlDataReader MyExecuteReader( this SqlCommand command )
 {
     var reader = command.ExecuteReader();
     if( reader.IsClosed() ) {
        throw new ClosedReaderReturnedException();
     }
     return reader;
 }

这很好,但我现在需要更改调用ExecuteReader()的所有代码,以便现在调用MyExecuteReader()并使维护更加困难。

有没有办法以某种方式声明我的任何代码都需要调用名为SqlCommand.ExecuteReader() MyExecuteReader()的代码?有效的是,可以用另一个具有完全相同签名和相同名称的方法替换现有方法吗?

4 个答案:

答案 0 :(得分:12)

不,不支持您想要的内容。如果类未密封且方法不是静态的,则可以在不同的命名空间中继承具有相同名称的类,并更改using,并覆盖该方法。但这是一个有限的解决方案。

您最好的选择是使用不同的名称实现标准扩展方法,并替换所有用法。这可能在大型代码库中看起来很多工作,并且可能会在未来发生人为错误 - 有人在原始方法中添加新调用。但是,一次性成本被您的代码现在明确表示您已对行为进行了修改这一事实所抵消;并且您可以通过编写自己的自定义FxCop规则(或者您经常运行的任何静态分析工具)来防止人为错误。

答案 1 :(得分:9)

这类似于尝试使用模拟单元测试代码时的问题。

其中一种方法是将代码中SqlCommand的使用替换为实现具有ExecuteReader方法的接口的对象。然后,您可以更轻松地替换对象,可能使用工厂模式。

所以你会替换这样的代码:

using (SqlCommand command = new SqlCommand(query))
{
    command.ExecuteReader();
}

使用:

var sqlCommandFactory = new SqlCommandFactory();
using (ISqlCommand command = sqlCommandFactory.CreateSqlCommand(query))
{
    command.ExecuteReader();
}

首先定义一个包含要替换的方法的接口:

public interface ISqlCommand
{
    SqlDataReader ExecuteReader();

    // further interface methods here...
}

然后创建一个工厂,它使用与SqlCommand构造函数相同的签名:

internal class SqlCommandFactory
{
    bool _useMyClass = true;

    public ISqlCommand CreateSqlCommand(string query)
    {
        if (_useMyClass)
        {
            return new MySqlCommand(query);
        }
        else
        {
            return new SqlCommandWrapper(query);
        }
    }
}

然后在MySqlCommand类中编写替代代码:

public MySqlCommand : ISqlCommand
{
    public SqlDataReader ExecuteReader()
    {
        // your new code here
    }
}

由于.NET SqlCommand类显然没有实现新的ISqlCommand接口,所以创建一个执行此操作的包装类:

public SqlCommandWrapper : ISqlCommand
{
    SqlCommand _sqlCommand;

    public SqlCommandWrapper(string query)
    {
        _sqlCommand = new SqlCommand(query);
    }

    public SqlDataReader ExecuteReader()
    {
        _sqlCommand.ExecuteReader();
    }
}

一些额外的工作,但这种方法的好处是您可以将实现更改为您想要的任何内容,包括单元测试(通过将模拟工厂传递给您的代码)。

额外的工作应该是一次性的,并根据要求保留名称和原始方法签名。这应该使您的代码看起来更熟悉,更容易理解(与自定义/扩展方法相比),尤其是当您(或您的团队)习惯这种众所周知的模式时。

答案 2 :(得分:3)

好吧,您可以使用像Cecil这样的库来重写IL,就像在这里完成的那样:http://plaureano.blogspot.dk/2011/05/introduction-to-il-rewriting-with-cecil.html?m=1

但我确实认为重写代码会更好一些,所以很明显其他人(以及后来自己)可能会阅读你的代码,发生了什么:)

答案 3 :(得分:1)

我不认为你想这样做。它会让所有阅读代码的人感到困惑。

但是,我相信它无法完成,但不能以任何好的或有保障的方式完成。回到过去,我们可以注入函数而不是DLL导出的函数。防病毒程序使用了这种技术。

显然,有人设法弄清楚如何inject .NET methods.

请记住,这可能比它的价值要大得多。您必须在安装了各种额外软件的各种平台上广泛地进行QA(一种防病毒软件可能会破坏您的代码)。实际上,只需按照其他人的建议去做 - 创建扩展方法,然后搜索并替换整个代码库。