Как автоматически генерировать код, который должен быть написан для каждого метода? - PullRequest
3 голосов
/ 29 июля 2010

Я работаю над проектом, и каждый отдельный метод, который я пишу, начинается с идентичного:

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
}

Каждый метод заканчивается по-разному в зависимости от того, что он делает, но я всегда начинаю с одной и той же структуры.Может кто-нибудь сказать мне, если есть способ автоматизировать написание этого кода, чтобы он не был таким повторяющимся?Может быть "Вставить фрагмент"?Если так, как я могу определить фрагменты?Спасибо.

Ответы [ 8 ]

4 голосов
/ 29 июля 2010

Вы можете посмотреть на решение AoP, например PostSharp .

3 голосов
/ 29 июля 2010

Вы могли бы использовать «Вставить фрагмент», но я думаю, что было бы предпочтительнее использовать что-то вроде PostSharp , чтобы реализовать это как перекрестный переход, а не дублировать код везде.

Вы бы сделали что-то вроде этого, что эффективно сгенерирует код, который у вас есть выше:

public class TraceAttribute : OnMethodBoundaryAspect
{
    public override void OnEntry(MethodExecutionEventArgs eventArgs)
    { 
        Tracing.StartOfMethod("Repository");
    }

    public override void OnExit(MethodExecutionEventArgs eventArgs)
    { 
        Tracing.EndOfMethod();
    }
}
2 голосов
/ 29 июля 2010

Как указывает Кент Бугаарт, это именно тот сценарий, для которого было изобретено Аспектно-ориентированное программирование. Таким образом, вы можете использовать это или просто использовать некоторый механизм сниппета для вставки кода в качестве шаблона в вашу IDE.

Однако я хотел бы сказать, что, на мой взгляд, это очень плохой стиль программирования. Наличие такого стандартного кода является тяжелым бременем для будущего обслуживания и читабельности кода.

Я призываю вас рассмотреть другие варианты. По крайней мере, вы можете поместить шаблонный код в метод "запуска" и сделать так, чтобы все вызовы методов проходили через метод запуска, который позаботится об этом.

В этом случае сам ваш шаблон уже кажется мне очень проблематичным:

  • Отслеживание каждого вызова метода кажется излишним. Если вам это действительно нужно, просто подключите отладчик, вот для чего они. Если вы хотите отслеживать вещи на производстве, гораздо полезнее иметь значимые сообщения журнала («Начало обработки frob ...», «обработанные объекты x glurg»). Это также поможет, например, sysadmins, тогда как ваши сообщения полезны, только если вы знаете исходный код.
  • Поймать все исключения в каждом методе, на мой взгляд, совершенно непростительно. Исключением является то, что вы можете позволить им распространяться. Ловите только локально исключения, которые вы можете обрабатывать индивидуально; остальное должно идти в общий обработчик вверх по стеку вызовов.

Возможно, вы могли бы объяснить вашу мотивацию для этого кода?

1 голос
/ 29 июля 2010

Я бы согласился с @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();
    }
}

Который можно назвать, например, лямбдой:

DoMethod(() => { return 5; }, ex => { return 0; })
0 голосов
/ 06 апреля 2012

Я позволю себе не согласиться с мнением, высказанным здесь о полезности ведения журнала и о проблемах использования фиксированного шаблона для каждой функции.

Основываясь на статье Джерри Деннани TraceListeners and Reflection , я расширил каркас логирования Object Guy , чтобы создать след моего кода с отступом. Это может быть дополнительно обработано средствами ведения журналов, но я не беспокоюсь - иногда очень полезно просто сканировать результаты.

Конечно, использование аспектного программирования - правильная вещь, но я так и не научился этому. поэтому я использую следующий фрагмент внутри каждого из моих методов для регистрации, проверки аргументов каждого метода и перехвата исключений (которые по умолчанию повторно генерируются)

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

0 голосов
/ 29 июля 2010

Вот фрагмент кода того, что вы могли бы хотеть. Просто создайте файл .snippet и поместите его в каталог сниппетов.

<?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>
0 голосов
/ 29 июля 2010

Вы можете посмотреть эту ссылку в MSDN, чтобы узнать, как создавать / использовать фрагменты.Я согласен с @Kent, хотя решение AOP будет лучшим.

0 голосов
/ 29 июля 2010

Доступны различные редакторы фрагментов, ни один из которых я никогда не использовал, но есть один в Codeplex, о котором я упоминал ранее: Редактор фрагментов .

...