Ostatnio odkryłem na nowo funkcjonalność definiowania własnym szablonów kodu. Funkcjonalność ta jest bardzo często nie wykorzystywana przez programistów, ale potrafi zdziałać cuda. W pisaniu aplikacji biznesowej zawsze przychodzi taki moment, że trzeba napisać kod służący do zapisywania danych do bazy, jak równię ich odczytywania.

W takim przypadku 90% kodu jest taka sama. Po pierwsze odczytujemy numer kolumny, w której przechowywane są dane w np. SQLDataReader. A następnie budujemy na podstawie danych obiekty. W trakcie odczytu danych z bazy należy oprogramować działanie w sytuacji gdy wystąpi null. I tu najczęściej sprawdza się czy w kolumnie odczytywanej występuje wartość null. Jeśli tak to podstawia się jakąś domyślną. Jeśli nie ma nulla to odczytuje się wartość z bazy.

I tu przychodzą z pomocą snippety. Cudowne szablony kodu, które pozwalają zminimalizować ilość czasu potrzebą na implementację dostępu do bazy. Zacznijmy od pierwszej części problemu. Kod w takiej sytuacji wygląda najczęściej tak:

SQLDataReader rdr = (...)
int id_ndx = rdr.GetOrdinal("id");
int name_ndx = rdr.GetOrdinal("name");
int surname_ndx = rdr.GetOrdinal("surname");
(...)

Następnie następuje najczęściej odczyt danych:

int id = rdr.IsDBNull(id_ndx) ? 0 : $reader$.GetInt32(id_ndx);
string name = rdr.IsDBNull(name_ndx) ? string.Empty : rdr.GetString(name_ndx);
string surname = rdr.IsDBNull(surname_ndx) ? string.Empty : rdr.GetString(surname_ndx);

Jak widać na powyższym przykładzie znaczna część kodu się powtarza. Zacznę więc od pierwszego przypadku. Zakładając, że chcemy, aby zmienne nazywały się tak samo jak kolumny w tabeli w bazie, tylko z końcówką „_ndx” można zaproponować następujące rozwiązanie:

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
   <CodeSnippet Format="1.0.0">
      <Header>
         <Title>GetOrdinalFromSQL</Title>
         <Shortcut>MGetOrdinal</Shortcut>
         <Description>Odczyt indexu kolumny z bazy danych</Description>
         <Author>Michal Jankowski</Author>
         <SnippetTypes>
            <SnippetType>Expansion</SnippetType>
         </SnippetTypes>
      </Header>
      <Snippet>
          <Declarations>
             <Literal>
                <ID>column</ID>
                <Default>columnname</Default>
                <ToolTip>Column name</ToolTip>
             </Literal>
          </Declarations>
          <Code Language="csharp"><!&#91;CDATA&#91;int $column$_ndx = rdr.GetOrdinal("$column$");
             $end$&#93;&#93;>
          </Code>
      </Snippet>
   </CodeSnippet>
</CodeSnippets>

A teraz krok po kroku co należy zrobić. Po pierwsze należy stworzyć plik XML o rozszerzeniu snippet. Następnie dodajemy standardowe rzeczy definiujące plik XML. Rzeczy ciekawe zaczynają się dopiero od elementu Header. W nim to definiuje się podstawowe informacje dotyczące snippetu:

  • Title – tytuł,
  • Shortcut – ciąg znaków, który będzie musiał zostać wprowadzony w Visual Studio aby zastosować dany snippet,
  • Description – opis snippetu,
  • Autor – informacje o autorze,
  • SnippetTypes– tu definiuje się sposób zachowania:
    • SurroundsWith – snippet może zostać zastosowany do wokół zaznaczonej części kodu,
    • Expansion – snippet może być użyty w miejscu kursora,
    • Refactoring – snippet jest używany w trakcie refaktoringu. Tego typu snippet nie może zostać zdefiniowany przez użytkownika.

Druga część pliku XML – element Snippet – definiują jak ma wyglądać snippet. Po pierwsze muszą zostać zadeklarowane zmienne, które będą używane w snippecie – element Declarations. W tym przypadku są dwie możliwości, zmienną można zadeklarować jako:

  • wartość tekstową – Literal,
  • obiekt – wtedy należy dodać sekcję Object.

Jak nazwa wskazuję, zmienne, których znamy typ powinniśmy zadeklarować jako obiekt. Dzięki temu zostanie wymuszone sprawdzanie typu wpisywanego obiektu. W naszym przykładzie nie jest to konieczne i dlatego też używane są tylko elementy Literal. Deklaracja zmiennej składa się z następujących elementów:

  • identyfikatora – ID,
  • wartości domyślnej jaką ma przyjąć – Default – tu należy się chwilę zastanowić i wpisać taką, która będzie najprawdopodobniej najczęściej wykorzystywana w kodzie,
  • podpowiedzi – ToolTip,
  • typu – Type – tylko w przypadku deklaracji zmiennej jako obiektu.

I na sam koniec wystarczy już tylko zdefiniować co dany snippet ma zrobić. Należy tylko pamiętać, że nazwę zmiennej zaczynami i kończymy znakiem $. Ciąg znaków $end$ określa miejsce gdzie znaleźć ma się kursor po wykonaniu snippetu.

Teraz pozostaje już tylko zaimportować snippet do Visual Studia (Tools – > Code Snippets Manager -> Import) i zacząć go używać. W tym celu wystarczy zacząć wpisywać tekst zdefiniowany w elemencie Shortcut. Jak tylko pojawi się nasz snippet naciskamy klawisz TAB i wpisujemy potrzebne informacje. Pomiędzy zmiennymi przejście następuje za pomocą klawisza TAB. Natomiast edycję koń czy naciśnięcie przycisku ENTER.

Z rzeczy, które zauważyłem to jest fakt, ze Visual Studio nie lubi jak są używane polskie znaki w snippetach. Nie miałem na sprawdzenie tego za dużo czasu, może pomogłaby zmiana kodowania, ale mi nie importowały się snippety, w których używałem polskich liter.

Na koniec zamieszczam jeszcze przykład snippetu do drugiej części problemu dla int:

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
   <CodeSnippet Format="1.0.0">
      <Header>
         <Title>GetIntFromSQL</Title>
         <Shortcut>MGetInt</Shortcut>
         <Description>Odczyt int z bazy danych</Description>
         <Author>Michal Jankowski</Author>
         <SnippetTypes>
            <SnippetType>Expansion</SnippetType>
         </SnippetTypes>
      </Header>
      <Snippet>
         <Declarations>
            <Literal>
               <ID>index</ID>
               <Default>column_ndx</Default>
               <ToolTip>Index</ToolTip>
            </Literal>
            <Literal>
               <ID>reader</ID>
               <Default>rdr</Default>
               <ToolTip>Wprowadz nazwe SQL readera</ToolTip>
            </Literal>
         </Declarations>
         <Code Language="csharp"><!&#91;CDATA&#91;$reader$.IsDBNull($index$) ? 0 : $reader$.GetInt32($index$);
            $selected$ $end$&#93;&#93;>
         </Code>
      </Snippet>
   </CodeSnippet>
</CodeSnippets>

Oraz jako pliki cały zestaw snippetów (dodatkowo odczyt z bazy typów: string, DateTime, double, decimal):