C# 关于代码复制的最佳实践#

C# 关于代码复制的最佳实践#,c#,code-duplication,C#,Code Duplication,我正试图以这样的方式构造代码,以减少/避免代码重复,我遇到了一个有趣的问题。每次我的代码调用存储过程时,我都需要传递一些存储过程所共有的变量:例如用户名、域、服务器ip和客户端ip。这些都来自HttpRequest对象或system.environment对象 由于这些都会传递给每个存储的进程,所以我最初的想法是创建一个实用程序类,它是一个数据库包装器,每次都会初始化并传递它们,所以我不必在代码中这样做。 问题是c#类(在App#u代码文件夹中)没有看到Httprequest对象。当然,我可以将

我正试图以这样的方式构造代码,以减少/避免代码重复,我遇到了一个有趣的问题。每次我的代码调用存储过程时,我都需要传递一些存储过程所共有的变量:例如用户名、域、服务器ip和客户端ip。这些都来自HttpRequest对象或system.environment对象

由于这些都会传递给每个存储的进程,所以我最初的想法是创建一个实用程序类,它是一个数据库包装器,每次都会初始化并传递它们,所以我不必在代码中这样做。 问题是c#类(在App#u代码文件夹中)没有看到Httprequest对象。当然,我可以将此作为参数传递给包装器,但这会破坏创建包装器的整个目的。我是不是遗漏了什么


我意识到每次调用存储过程时重复4行代码并不是什么大不了的事,但我更愿意在非常早期的阶段消除代码重复

HttpContext.Current与您在HttpRequest中找到的信息类似,更重要的是,它可以在App_代码中找到。

我会按照您现在的方式保存它。它更干净,更容易扩展/修改,更容易进行单元测试


至于像其他人建议的那样使用HttpContext,我认为这是一个坏主意。一旦您开始在HttpContext上的域中引入依赖项,就很难消除它。如果以后您想在没有HttpContext的情况下使用模块,该怎么办?单元测试怎么样?

尝试System.Web.HttpContext.Current.Request获取当前请求。

这里有一个奇怪的想法,你可能喜欢,也可能不喜欢:定义一个“profile”类和一个函数,该函数将profile扩展为使用公共参数的函数的参数

class P {
    readonly string name;
    readonly string domain;
    public P(string name, string domain) {
        this.name = name; this.domain = domain;
    }
    public void inject(Action<string, string> f) {
        f(p.arg1, p.arg2);
    }
    public T inject<T>(Func<string, string, T> f) {
        return f(p.arg1, p.arg2);
    }
}
P类{
只读字符串名称;
只读字符串域;
公共P(字符串名称、字符串域){
this.name=name;this.domain=domain;
}
公众参与(行动f){
f(p.arg1,p.arg2);
}
公共T注入(功能f){
返回f(p.arg1,p.arg2);
}
}

在VB.net中,如果有AddressOf操作符,它可能会工作得更好。我会非常谨慎地使用这种类型的东西,因为你很容易破坏可读性和封装性。

作为一般规则,不管编程语言如何,如果你可以眯起眼睛,代码看起来是一样的,你应该从中生成一个函数/方法/消息,并传递参数


还有一件事要看,一旦你有了接受大量参数的方法(4是一个很好的经验法则,但它确实是一个个案的基础),是时候让该方法接受一个对象作为参数,而不是单独的参数。99.99999999999999999999%的时间,这样的对象应该是不可变的(没有可写的实例变量)。

您可能正在走下坡路。DRY的要点是不要在多个地方重复业务逻辑,因为需求的变化需要在多个相似的地方更改代码。如果这4行是上下文相关的,那么您不必仅仅因为这4行是相同的就进行重构。您还通过引用httprequest破坏了封装,因为您使用的是全局变量。作为you类的消费者,我必须知道实现细节,我只能从web应用程序调用您

这就是说,如果您考虑到这一点,并且仍然希望继续,那么这里有另一个类似于这样的信息选项。创建包含所需属性的自定义SecurityPrincipal(实现IPrincipal),并将其附加到线程。当用户登录时填写它们,然后您可以在请求期间的任何位置访问它。您的调用者仍然需要确保已完成此操作,但至少它不是特定于平台的


否则,为了实现最佳封装,请将具有所需属性的类传递到每个需要使用这些属性的对象的构造函数中。

将数据层设置为从包含这些值的4个属性的基类继承。使公共构造函数需要这4个属性

然后使用构造函数中的这4个属性在业务层基类中执行类似的操作

然后UI执行新的BusObj(请求[“用户名”],…).method()


在数据层中,您可以使用一个方法构建一个包含这4个属性的SQLParameter数组,然后每个方法都可以向数组中添加其他参数。

我们试图实现的一个目标是强制将这4个参数传递给每个存储过程(审计目的)所以灵活性在这里不是一个大问题,但当然是要考虑的问题。