代码复制的最佳实践c#

时间:2009-02-26 01:13:49

标签: c# code-duplication

我正在尝试以减少/避免代码重复的方式构建我的代码,并且遇到了一个有趣的问题。每次我的代码调用存储过程时,我都需要传递一些常见的存储过程变量:例如username,domain,server_ip和client_ip。这些都来自HttpRequest对象或system.environment对象。

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

我意识到每次调用存储过程时重复4行代码并不是一件大事,但我宁愿在最初阶段消除代码重复。

7 个答案:

答案 0 :(得分:4)

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

然后在业务层中做类似的事情 - 在构造函数中使用这4个属性的基类。

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

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

答案 1 :(得分:3)

作为一般规则,无论编程语言如何,如果你可以眯起眼睛并且代码看起来相同,你应该从中发出一个函数/方法/消息并传递参数。

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

答案 2 :(得分:2)

HttpContext.Current与您在Http请求中找到的信息类似,更重要的是在App_Code中可用。

答案 3 :(得分:2)

这是一个你可能喜欢或不喜欢的奇怪想法:定义一个'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);
    }
}

在拥有AddressOf运算符的VB.net中可能会更好。我会非常谨慎地使用这种类型的东西,因为你很容易损害可读性和封装。

答案 4 :(得分:1)

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

至于像其他人所建议的那样使用HttpContext,我会说这是一个坏主意。一旦你开始在你的域中在HttpContext上引入依赖关系,就很难把它拿出来。如果你以后想要在没有HttpContext的情况下使用你的模块怎么办?单元测试怎么样?

答案 5 :(得分:1)

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

答案 6 :(得分:1)

你可能正在滑坡。对DRY的要点是不要在多个地方重复业务逻辑,其中需求的变化需要在多个类似的地方更改代码。您不必重构仅因为4行是相同的,如果这4行是依赖于上下文的。您还通过引用httprequest来破坏封装,因为您正在使用全局变量。作为您的消费者,我必须知道我只能通过Web应用程序呼叫您的实现细节。

话虽如此,如果你考虑到这一点并仍想继续,这里是另一个选择这样的信息。创建一个包含所需属性的自定义SecurityPrincipal(实现IPrincipal)并将其附加到该线程。在用户登录时填写它们,然后您可以在请求期间随时随地访问它。您的调用者仍然需要确保已完成此操作,但至少它不是特定于平台的。

否则,为了获得最佳封装,请将具有所需属性的类传入构造函数中,以用于需要使用这些属性的每个对象。