我正在研究一个项目,我写的每一个方法都与:
相同public blah blah() // my method signature
{
Tracing.StartOfMethod("Repositroy");
// I'll declare variables as needed
try
{
// the content here differs for every method
}
catch (Exception ex)
{
ErrorSignal.FromCurrentContext().Raise(ex);
// sometimes I'll add something here
}
finally
{
// sometimes something here
Tracing.EndOfMethod();
}
// return result
}
每种方法的结果都不同,具体取决于它的作用,但我始终以相同的结构开始。有人能告诉我是否有办法自动编写这段代码,所以它不是那么重复?也许“插入片段”?如果是这样,我该如何定义片段?感谢。
答案 0 :(得分:4)
您可以查看AoP解决方案,例如PostSharp。
答案 1 :(得分:3)
您可以使用“插入代码段”,但我认为最好使用PostSharp这样的内容来实现横切,而不是在任何地方都有重复的代码。
你会做这样的事情,这将有效地生成你上面的代码:
public class TraceAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionEventArgs eventArgs)
{
Tracing.StartOfMethod("Repository");
}
public override void OnExit(MethodExecutionEventArgs eventArgs)
{
Tracing.EndOfMethod();
}
}
答案 2 :(得分:2)
正如Kent Boogaart指出的那样,这只是面向方面编程发明的场景。因此,您可以使用它,或者只使用一些代码段机制将代码作为模板插入IDE中。
但是,我想说在我看来这是一个非常糟糕的编程风格。像这样的样板代码是未来维护和代码可读性的沉重负担。
我恳请你考虑其他选择。至少,您可以将样板代码放入“启动器”方法,并通过启动器方法调用所有方法,这将解决此问题。
在这种情况下,你的样板本身已经让我感到非常困难:
也许您可以解释一下这段代码的动机?
答案 3 :(得分:1)
我同意@Kent和其他人认为AoP在这里看起来很好,而且对于@sleske来说,必须在每种方法上做到这一点都表明你可能有设计问题。
话虽如此,只是为了给你一个替代方案,我在类似的情况下做的一件事(虽然不是每个方法都是)定义一个带有样板代码的方法,然后通过一个'有用的'代码传递委托:
public T DoMethod<T>( Func<T> mainCode, Func<Exception, T> exceptionHandlerCode)
{
Tracing.StartOfMethod("Repository");
try
{
return mainCode.Invoke();
}
catch (Exception ex)
{
ErrorSignal.FromCurrentContext().Raise(ex);
return exceptionHandlerCode.Invoke(ex);
}
finally
{
// sometimes something here
Tracing.EndOfMethod();
}
}
例如,可以使用lambda:
调用DoMethod(() => { return 5; }, ex => { return 0; })
答案 4 :(得分:0)
我可以使用各种代码段编辑器,但我从未使用过这些编辑器,但我之前看到的Codeplex上有一个代码编辑器:Snippet Editor。
答案 5 :(得分:0)
您可以在MSDN上查看this link有关如何创建/使用代码段的信息。我同意@Kent,尽管AOP解决方案是最好的。
答案 6 :(得分:0)
以下是您可能需要的代码段示例。 只需创建一个.snippet文件并将其放在snippets目录中。
<?xml version="1.0" encoding="utf-8"?> <CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> <CodeSnippet Format="1.0.0">
<Header>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
<Title>commonmethodsnippet</Title>
<Shortcut>commonmethodsnippet</Shortcut>
<Description>Common method snippet.</Description>
<Author>Me</Author>
</Header>
<Snippet>
<Declarations>
<Literal Editable="true">
<ID>returnValue</ID>
<ToolTip>Return Value</ToolTip>
<Default>returnValue</Default>
<Function>
</Function>
</Literal>
<Literal Editable="true">
<ID>methodName</ID>
<ToolTip>Method Name</ToolTip>
<Default>methodName</Default>
<Function>
</Function>
</Literal>
<Literal Editable="true">
<ID>methodDescription</ID>
<ToolTip>Method Description</ToolTip>
<Default>methodDescription</Default>
<Function>
</Function>
</Literal>
<Literal Editable="true">
<ID>variableDeclarations</ID>
<ToolTip>Variable Declarations</ToolTip>
<Default>variableDeclarations</Default>
<Function>
</Function>
</Literal>
</Declarations>
<Code Language="csharp"><![CDATA[public $returnValue$ $methodName$() // $methodDescription$ {
Tracing.StartOfMethod("Repository");
// Variable Declarations
$variableDeclarations$
try
{
// the content here differs for every method
}
catch (Exception ex)
{
ErrorSignal.FromCurrentContext().Raise(ex);
// sometimes I'll add something here
}
finally
{
// sometimes something here
Tracing.EndOfMethod();
}
// return result }]]></Code>
</Snippet> </CodeSnippet> </CodeSnippets>
答案 7 :(得分:0)
我不同意这里提出的关于日志记录的有用性以及为每个函数使用固定模板的问题的意见。
根据Jerry Dennany的文章TraceListeners and Reflection,我扩展了the Object Guy's logging framework以产生我代码的缩进痕迹。这可以通过记录工具进一步处理,但我不打扰 - 扫描结果有时候非常有建设性。
当然,使用方面编程是正确的事情,但我从来没有学过它。所以我在我的每个方法中都有以下片段来记录,验证每个方法的参数,并捕获异常(默认情况下会被重新抛出)
<CodeSnippet Format="1.0.0">
<Header>
<Title>Canonic</Title>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>ClassName</ID>
<ToolTip>Replace with the name of the class.</ToolTip>
<Default>ClassName</Default>
</Literal>
<Literal>
<ID>MethodName</ID>
<ToolTip>Replace with the name of the method.</ToolTip>
<Default>MethodName</Default>
</Literal>
<Literal>
<ID>FirstArgName</ID>
<ToolTip>Replace with the name of the first argument.</ToolTip>
<Default>FirstArgName</Default>
</Literal>
<Literal>
<ID>SecondArgName</ID>
<ToolTip>Replace with the name of the second argument.</ToolTip>
<Default>SecondArgName</Default>
</Literal>
<Literal>
<ID>ResultName</ID>
<ToolTip>Replace with the name of the result.</ToolTip>
<Default>ResultName</Default>
</Literal>
</Declarations>
<Code Language="CSharp">
<![CDATA[ Logger.LogMethod("$FirstArgName$", $FirstArgName$,"$SecondArgName$", $SecondArgName$);
try
{
Validator.Verify($FirstArgName$, $SecondArgName$);
//VerifyFields();
Logger.LogReturn($ResultName$);
return $ResultName$;
}
#region Exception
catch (Exception exp)
{
Logger.LogException("$ClassName$.$MethodName$", exp);
throw;
}
#endregion Exception
]]>
</Code>
</Snippet>