C#中代码重复的最佳实践

3
我试图以一种结构化的方式减少/避免代码重复,但我遇到了一个有趣的问题。每次我的代码调用一个存储过程时,我需要传递一些变量,这些变量是存储过程共有的,如用户名、域、服务器IP和客户端IP,这些都来自HttpRequest对象或system.environment对象。
由于这些变量需要被传递到每个存储过程中,我的最初想法是创建一个实用类作为数据库包装器,并在每次初始化后传递这些变量,这样我就不必在代码中编写它们。然而问题在于C#类(位于App_Code文件夹中)无法看到HttpRequest对象。当然,我可以将其作为参数传递给包装器,但这将失败创建包装器的整个目的。我错过了什么吗?
我意识到每次调用存储过程重复4行代码并不是什么大问题,但我宁愿在早期阶段消除代码重复。
7个回答

4

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

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

然后UI执行new BusObj(Request [“username”],...)。method()。

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


3
作为一个普遍规则,无论使用哪种编程语言,如果你眯起眼睛看代码都一样,那么你应该将其制作成函数/方法/消息,并传递参数。
另外,当你有一些需要大量参数(4个是一个好的经验法则,但这绝对是因情况而异)的方法时,就该考虑将该方法作为一个对象参数传入,而不是单独的参数。99.99999999999999999999%的时间,这样的对象应该是不可变的(没有可写的实例变量)。

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

在VB.net中,您可以使用AddressOf运算符来更好地实现此操作。但是,我建议您谨慎使用此类操作,因为这可能会破坏代码的可读性和封装性。


2

HttpContext.Current包含与HttpRequest中相似的信息,更重要的是它可以在App_Code中使用。


1

我会保持现在的方式。它更清晰,更容易扩展/修改,也更容易进行单元测试。

至于像其他人建议的使用HttpContext,我认为这是一个坏主意。一旦你开始在你的域中引入HttpContext的依赖,就很难将其移除。如果以后你想在没有HttpContext的情况下使用你的模块怎么办?如何进行单元测试呢?


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

1
你可能正在走下一条滑坡。DRY的重点是不要在多个地方重复业务逻辑,因为需求变化会导致需要在多个相似的地方更改代码。如果这四行代码是上下文相关的,那么你不一定要重构。你还通过引用httprequest打破了封装性,因为你使用了全局变量。作为你类的消费者,我必须知道实现细节,才能从Web应用程序中调用你。
话虽如此,如果你考虑到这一点仍然想继续,这里有另一个选项可以获取这样的信息。创建一个自定义SecurityPrincipal(实现IPrincipal),其中包含你需要的属性,并将其附加到线程上。当用户登录时填充它们,然后您可以在请求期间的任何地方访问它们。你的调用者仍然需要确保这样做,但至少它不是特定于平台的。
否则,为了最好的封装性,将具有所需属性的类传递到每个需要使用这些属性的对象的构造函数中。

我们正在努力实现的一件事情是强制要求将这4个参数传递给每个存储过程(出于审计目的)。因此,灵活性并不是一个很大的问题,但肯定需要考虑。 - sarsnake

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接