Reputation: 42175
I'm working on a project and every single method I write starts off identical to:
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
}
Every method ends up differently depending on what it does, but I always start with the same structure. Can somebody tell me if there's a way to automate writing this code so it's not so repetitive? Maybe "Insert Snippet"? If so, how do I define snippets? Thanks.
Upvotes: 3
Views: 410
Reputation: 16176
I beg to differ with opinions raised here about the usefulness of logging, and about the problems of using a fixed template for each function.
Base on the Jerry Dennany's article TraceListeners and Reflection, I've extended the Object Guy's logging framework to produce an indented trace of my code. This can further be processed by logging tools but I don't bother - It's sometimes very constructive just to scan the results.
Of course, using aspect programming is the correct thing to do, but I never got to learning it. so I'm uisng the following snippet inside each and every of my methods to log, to verify each method's arguments, and to catch exceptions (which, by default, are re-thrown)
<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>
Upvotes: 0
Reputation: 9101
I would agree with @Kent and the others that AoP looks good here, and also with @sleske that having to do this on every method suggests you might have design issues.
Having said that, just to give you an alternative, one thing I did in a similar situation (although not for every method) was to define a method with the boilerplate code in, and pass the 'useful' code in via a delegate:
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();
}
}
Which could be called, for example, with a lambda:
DoMethod(() => { return 5; }, ex => { return 0; })
Upvotes: 1
Reputation: 83587
As Kent Boogaart points out, this is just the scenario that Aspect Oriented Programming was invented for. So you can either use that, or just use some snippet mechanism to insert the code as a template in your IDE.
However, I would like to say that in my opinion this is a very bad programming style. Having boilerplate code like this is a heavy burden for future maintenance and readability of the code.
I urge you to consider other options. At the least, you could put the boilerplate code into a "launcher" method, and have all methods call pass via the launcher method, which takes care of this.
In this case, your boilerplate itself already strikes me as very problematic:
Perhaps you could explain your motivation for this code?
Upvotes: 2
Reputation: 591
Here is a snippet example of what you might want. Just create a .snippet file and put it in the snippets directory.
<?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>
Upvotes: 0
Reputation: 6809
You could use "Insert Snippet", but I would think it would be preferable to use something like PostSharp to implement this as cross-cut rather than have the duplicated code everywhere.
You would do something like this, which would effectively generate the code you have above:
public class TraceAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionEventArgs eventArgs)
{
Tracing.StartOfMethod("Repository");
}
public override void OnExit(MethodExecutionEventArgs eventArgs)
{
Tracing.EndOfMethod();
}
}
Upvotes: 3
Reputation: 18353
You can look at this link on MSDN for how to create/use snippets. I agree with @Kent though that an AOP solution would be best.
Upvotes: 0
Reputation: 45771
There's various snippet editors available, none of which I've ever used but there is one on Codeplex that I've seen mentioned previously: Snippet Editor.
Upvotes: 0