C# 关于C“的风格/可读性问题;使用;陈述

C# 关于C“的风格/可读性问题;使用;陈述,c#,coding-style,using-statement,C#,Coding Style,Using Statement,我想知道你对编码风格的看法,我对此持怀疑态度。我意识到可能没有一个明确的答案,但我想看看在一个方向上是否有强烈的偏好 我正在研究一个解决方案,在很多地方使用语句添加。我经常会遇到这样的事情: { log = new log(); log.SomeProperty = something; // several of these log.Connection = new OracleConnection("..."); log.InsertData(); // t

我想知道你对编码风格的看法,我对此持怀疑态度。我意识到可能没有一个明确的答案,但我想看看在一个方向上是否有强烈的偏好

我正在研究一个解决方案,在很多地方使用语句添加
。我经常会遇到这样的事情:

{
    log = new log();
    log.SomeProperty = something;  // several of these
    log.Connection = new OracleConnection("...");
    log.InsertData(); // this is where log.Connection will be used
    ... // do other stuff with log, but connection won't be used again
}
其中log.Connection是一个OracleConnection,它实现IDisposable

我体内的neatnik想要将其更改为:

{
    using (OracleConnection connection = new OracleConnection("..."))
    {
        log = new log();
        log.SomeProperty = something;
        log.Connection = conn;
        log.InsertData();
        ...
    }
}
但是,爱简洁、做事稍微快一点的人想要做到:

{
    log = new log();
    log.SomeProperty = something; 
    using (log.Connection = new OracleConnection("..."))
        log.InsertData();
    ...
}
出于某种原因,我觉得这样做有点脏。你认为这不好吗?如果你认为这很糟糕,为什么?如果是好的,为什么


EDIT:请注意,这只是众多例子中的一个(有点做作)。请不要拘泥于这样一个事实,即这恰好表明一个日志程序类具有一个考虑不周的接口。这与我的问题无关,无论如何,我也不能自由地改进课程本身。

我会倾听你内心的渴望。我个人更喜欢他的方式。

他们都很可怕。两个都不要

你在这里做我称之为“”的东西。高级维护课程有一个合同,上面写着“我需要你给我一堆资源,你需要知道我什么时候处理完它们,并适当地清理它们”。这个契约意味着类的用户必须知道类是如何实现的,从而违反了封装和抽象的原则,而封装和抽象是创建类的首要动机

您可以从您的评论中看出这一点:这是使用连接的地方,我知道该连接将不再使用。你怎么知道的?您只知道,如果这是类的文档化契约。这不是一个好的合同强加给消费者的一类

有一些方法可以改善这一点:

1) 使记录器成为一次性的。完成后,让它清理连接。缺点是记录器保持连接的时间超过了必要的时间

2) 使InsertData将连接作为参数。调用方仍然可以负责清理连接,因为记录器没有保持连接


3) 制作第三类“插入器”,它是一次性的,并在其构造函数中获取日志和连接。插入器在处理连接时处理连接;然后调用方负责处理插入器。

如果
log
实现了IDisposable,则执行第二个选择,因为大括号是显式的。在某些情况下,您可以使用多个
语句:

using (Graphics g = ...)
using (Pen p = new Pen ...)
using (Font f = new Font ...)
{



}

在这里,您只需使用一套大括号就可以脱身。这避免了疯狂的缩进。

使用
的两种方法完全相同。无论哪种方式,最终都会得到一个仍在作用域中但已释放连接的日志。更好的办法是使日志可丢弃,并让其dispose方法处理其连接,将日志放在using语句中,而不是连接本身。

我同意理想情况下
log
本身应该实现
IDisposable
,但让我们假设这是不可能的,并解决OP实际提出的问题

第二种方法更好,原因很简单,完成相同任务的代码更少。在这里引入额外的
连接
变量没有任何好处

还请注意,您可以使用
块在
之外进行其他初始化。这在这里并不重要,但如果你正在“使用”一些非常昂贵的资源,这可能会很重要。即:

log = new log();
log.SomeProperty = something; // This can be outside the "using"
using (OracleConnection connection = new OracleConnection("..."))
{
    log.Connection = conn;
    log.InsertData();
    ...
}

这很有趣,因为我发现大多数时候的经验法则是“如果你创建了它,那么你的工作就是处理它。”如果日志记录者处理了一个可能被其他日志记录者共享或不被共享的连接,我会更惊讶。例如,我已经有一段时间没有直接使用SqlCommand了,但是如果我记得的话,它不会处理您传递给它的连接。@Josh:如果您想共享,请执行选项#2。连接不应该是日志的成员。@Josh:将其与流读取器进行比较,流读取器拥有对正在读取的流的处理。重要的是合同不难或不令人惊讶。我会惊讶地发现,一个日志记录者持有对已处置集合的引用;我如何知道记录器已经完成了?不幸的是,这些改进超出了我当前任务的范围。我很想在这个解决方案中做很多这样的更改,但我目前还没有被指派这样做。然而,这只是许多例子中的一个。其他一些案例确实符合你的第二个建议。考虑到这些因素,我仍然希望你能对我最初的问题发表意见。这很公平,但是NetworkStream在构造函数中给了你一个明确的选项,你是否给了它套接字的“所有权”。我喜欢你的#2建议,但#1对我来说似乎同样模糊。因为第二种方式对我来说非常难看,我对代码的“外观”非常挑剔。好吧,un-1诚实。没关系,我觉得这个问题没有正确的答案,这就是为什么我在社区维基上标记了我的答案。:)谢谢你回答实际问题。您关于在using块之外执行初始化的观点很有趣,因为我将它移到块内的唯一原因是我觉得将所有相关代码放在一起更整洁。我并没有考虑到潜在的费用(这里不是一个问题,但要记住这一点),日志并没有实现IDisposable。考虑到这一点,你会更喜欢“整洁”的第一选择吗?然后接受埃里克·利珀特的建议。他在这方面几乎是个马屁精。如果我是他,埃里克的建议会很好