views:

135

answers:

7

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.

+3  A: 

You could look at an AoP solution, such as PostSharp.

HTH,
Kent

Kent Boogaart
A: 

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.

Rob
+2  A: 

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();
    }
}
consultutah
I was thinking about that, but it really only gets rid of the trace statement at the top, which (while useful) isn't the majority of the problem. Is there a way to use AOP to get rid of the repeated exception handling code as well?
Grant Crofton
You would do an OnExceptionAspect that implements the duplicate code. On the link above, click on the "Exception" tab to see an example.
consultutah
Yeah I checked that out, but I didn't see how it would fit in with the OPs need to have custom code in the error handler.
Grant Crofton
You're right: if the code that you add in the exception requires access to method parameters or variables, you might not be able to do it.
consultutah
A: 

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.

TheCloudlessSky
A: 

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"&gt; <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>
Dusty Lau
+2  A: 

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:

  • Tracing every method call seems like overkill. If you really need this, just attach a debugger, that's what they are for. If you want to trace stuff in production, it's way more helpful to have meaningful log messages ("Starting frob processing...", "processed x glurg objects"). These will also help e.g. sysadmins, whereas your messages are only useful if you know the source code.
  • Catching all exceptions in every method is in my opinion totally inexcusable. The point of exceptions is that you can let them propagate. Only catch locally the exceptions which you can handle individually; the rest should go to a generic handler up the call stack.

Perhaps you could explain your motivation for this code?

sleske
@sleske, ok so maybe I'm exagerating when I say 'every single method', but a lot of them do, particularly in the repository classes. We're currently working in an organisation where the philosophy from the higher-ups is 'just do it', rather than 'do it right', so we don't often get feedback on the quality of the code. As developers we'd like to be better than 'just do it' so I'll take your suggestions into consideration.
DaveDev
@DaveDev: Always glad to help :-). I realize there may be situations where this technique is the best you can do. I can just say that personally I would fight any such mandate tooth and nail.
sleske
@DaveDev: And if I may venture another personal remark: This sounds like there is way too much micromanaging in your organization...
sleske
+1  A: 

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; })
Grant Crofton
+1 That's what I had in mind when I wrote of a "launcher" method in my answer. But you actually worked it out.
sleske
Also, a nice example of using lambdas :-).
sleske
Thanks :-). I don't use lambdas that much , but it's nice to find a situation where they're useful.
Grant Crofton