Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 方法内的日志记录以何种方式容易出错和侵入?_C#_Aop - Fatal编程技术网

C# 方法内的日志记录以何种方式容易出错和侵入?

C# 方法内的日志记录以何种方式容易出错和侵入?,c#,aop,C#,Aop,我正在读这本书,作者加里·麦克莱恩·霍尔说: [日志记录和事务性代码]费时费力且容易出错,而且会立即污染每一个应用程序 方法使用不相关的样板代码,增加 噪声信号比。相反,您可以考虑这样的交叉 将关注点转换为封装的功能,并将其应用于中的代码 一种侵入性小得多的时尚。最常见的添加方式 功能是通过面向方面的编程实现的 对于此代码: 我知道这很费劲,而且它会做方法名没有指明的事情,比如日志记录,但我不明白为什么它容易出错。也许是因为你经常重复自己 他的建议是使用以下代码: 但是,如果您只是在寻找一个通用

我正在读这本书,作者加里·麦克莱恩·霍尔说:

[日志记录和事务性代码]费时费力且容易出错,而且会立即污染每一个应用程序 方法使用不相关的样板代码,增加 噪声信号比。相反,您可以考虑这样的交叉 将关注点转换为封装的功能,并将其应用于中的代码 一种侵入性小得多的时尚。最常见的添加方式 功能是通过面向方面的编程实现的

对于此代码:

我知道这很费劲,而且它会做方法名没有指明的事情,比如日志记录,但我不明白为什么它容易出错。也许是因为你经常重复自己

他的建议是使用以下代码:


但是,如果您只是在寻找一个通用的记录器,那么您可以调用类似于
\u log.log()
的方法,这是相对相同的工作量。除非属性具有检查方法实现的能力,否则在这种情况下,我看不到它们有多大价值,只是它们提供了更具描述性的代码。

我同意作者的观点,即它容易出错。一个非常重要的原因是简单。通过对您在这里给出的两个示例进行粗略的分析,很明显,第二个实现更易于维护和理解。想象一下向方法中添加一个新参数:(我假设Logged属性也负责记录参数),如果要用代码将其记录在方法中,则必须在心里解析格式字符串、添加参数等,并且所做的任何更改都很容易出错。此外,当您使用多种方法编写此代码时,很容易有人遗漏某些参数和/或以错误的顺序传递参数。

任何时候,您需要代码执行某个操作的多个操作时,如果忘记一个参数或将参数弄错,则可能会导致潜在的错误。如果您添加的代码重复但不完全相同,则尤其如此。在十几个地方这样做,一切看起来都一样。当您从其他地方复制/粘贴代码时,需要花费很长时间才能确定是否忘记更改参数

与属性一起使用的声明性方法消除了所有这些bug源。你不会意识到这些好处,直到你花了几个小时追踪一个bug,却发现你在复制/粘贴后忘记了编辑。这是一种经验,在很大程度上取决于您使用的代码的大小。对于小代码来说没有区别,添加显式代码更容易理解,尤其是当您正在学习时。在大型代码库中,由于需要大量维护,每一行都可能引入一个bug,因为附近代码的每一次更改都可能需要更改锅炉板代码

至于污染代码,这也是事实。您必须略读这些内容,以关注代码的主要目的。样板代码只是碍事。同样,大小取决于代码库的大小和复杂性

我建议你做对你有用的事情,当你开始觉得必须有更好的方法时,再重新阅读旧的建议,看看它们现在是否更有意义。试图把它当作一个假设性的问题来考虑几乎是不可能的,除非你有了战斗的伤疤,让它变得个人化和相关,否则是没有意义的

以日志记录为例。这被认为是横切的,因为日志记录策略会影响已记录系统的每个部分(至少它必须将其考虑在内)。在这方面,系统的每个部分都需要考虑一些事情,这意味着更改日志记录意味着您必须更改系统中记录日志的每个部分(例如添加更多相关信息)。(此外,如果忘记记录重要内容,可以称之为容易出错)。在实践中,日志记录通常是良性的,因此它会导致一个平淡无奇的示例,并被称为容易出错

我认为一个更好的例子是检查安全性。我不认为这是一个很大的延伸,看看如何剪切和粘贴安全代码到处都可能是容易出错的,并更新该代码可能会变得很难得到正确的

如果您需要更改安全/权限的实现方式(在非方面世界中),您(可以想象)需要重新访问进行安全检查的每个地方,因为安全检查分散在整个程序中。纠缠设计使得从设计/维护的角度考虑所有可能的交互变得困难。如果您有[CheckSecurity]属性,那么就不会有太多的纠葛,也不需要重新访问需要检查安全性的每个函数

这里的关键是方面将在编译时/运行时基于检查来更改代码。因此,如果需要更改安全凭据的检查方式,则只需转到代码中的一个位置。这与只使用一个方法/函数进行安全检查有很大的不同,因为函数不能检查它们的堆栈并根据调用者来改变它们的行为。c#can中的代码注入


这是一篇PostSharp和一篇

很好的描述,很好的链接和很酷的播客,适合像我这样的播客迷+1在第一个代码块中的
log.WriteInfo
结尾处似乎有一个错误的引号。
public void OpenNewAccount(Guid ownerID, string accountName, decimal openingBalance)
{
    log.WriteInfo("Creating new account for owner {0} with name '{1}' and an opening balance of {2}", ownerID, accountName, openingBalance");

    using(var transaction = session.BeginTransaction())
    {
        var user = userRepository.GetByID(ownerID);
        user.CreateAccount(accountName);
        var account = user.FindAccount(accountName);
        account.SetBalance(opening Balance);

        transaction.Commit();
    }
}
[Logged]
[Transactional]
public void OpenNewAccount(Guid ownerID, string accountName, decimal openingBalance)
{
    var user = userRepository.GetByID(ownerID);
    user.CreateAccount(accountName);
    var account = user.FindAccount(accountName);
    account.SetBalance(opening Balance);
}