DaveDev
DaveDev

Reputation: 42175

How to automatically generate code that has to be written for every method?

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

Answers (8)

Avi
Avi

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

Kent Boogaart
Kent Boogaart

Reputation: 178650

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

Upvotes: 4

Grant Crofton
Grant Crofton

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

sleske
sleske

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:

  • 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?

Upvotes: 2

Dusty Lau
Dusty Lau

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

ConsultUtah
ConsultUtah

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

TheCloudlessSky
TheCloudlessSky

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

Rob
Rob

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

Related Questions