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

本文关键字:方法 替换 另一个 我可以 | 更新日期: 2023-09-27 17:51:13

我有以下情况。一些。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()被调用?是否可以有效地将现有方法替换为具有完全相同签名和相同名称的另一个方法?

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

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

最好的选择是用不同的名称实现标准的扩展方法,并替换所有的用法。在大型代码库中,这似乎需要做很多工作,并且可能容易出现人为错误——有人向原始方法添加了新的调用。然而,你的代码现在明确地表明你已经对行为进行了修改,这一事实抵消了一次性成本;您可以通过编写自己的自定义FxCop规则(或您经常运行的任何静态分析工具)来防止人为错误。

这与尝试使用mock对代码进行单元测试时出现的问题类似。

解决这个问题的一种方法是用一个对象来实现带有ExecuteReader方法的接口,从而取代代码中SqlCommand的使用。然后可以更容易地替换对象,也许可以使用工厂模式。

所以你可以这样替换代码:

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

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

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

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

但是我相信重写你的代码是更好的方式,这样任何人(以及你自己)都可以清楚地看到你的代码,发生了什么:)

我想你不会想这么做的。这会让所有读代码的人感到困惑。

然而,我相信这是不可能做到的,但不是以任何好的或保证长期支持的方式。在过去,我们可以注入函数而不是dll导出的函数。防病毒程序使用这种技术。

显然,有人设法弄清楚如何注入。net方法。

请记住,这可能会比它的价值更多的麻烦。你必须在安装了各种额外软件的各种平台上进行广泛的QA(一种杀毒软件可能会破坏你的代码)。所以,按照其他人的建议去做——创建你的扩展方法,然后搜索并替换你的整个代码库。