Skocz do zawartości

wiesniak@Blog.FA

  • wpisy
    12
  • komentarzy
    134
  • wyświetleń
    40063

Snippety w Visual Studio


wies.niak

1582 wyświetleń

Hejo!

Ten mały wpis jest z dedykacją dla mojej dobrej koleżanki z pracy (i świetnej programistki!) Anety, dzięki której zainteresowałem się tematem i dziś nie wyobrażam sobie pracy bez snippetów. Dziękuję za lekcję :-)

Plan na ten wpis to:

  • opisać co to w ogóle snippet
  • pokazać, jak się ich używa
  • opisać wbudowane snippety
  • pokazać jak się tworzy własne

Czym więc są snippety? Mówiąc prosto, są to szablony kodu przyspieszające pisanie stałych elementów typu właściwości, pętle itd. Visual Studio posiada własny zbiór snippetów, ale każdy może w notatniczku napisać sobie własne szablony. Zła wiadomość dla dla programistów C++: Visual Studio 2010 nie obsługuje snippetów dla tego języka. Wspierane są snippety dla HTML, ASP.NET, JScript, SQL, XML, VB, oraz oczywiście C#. Nie zamierzam robić z tego wpisu kompendium, więc osoby zainteresowane wszystkimi niuansami tworzenia snippetów zapraszam na stronę http://msdn.microsoft.com/en-us/library/ms...2(v=vs.80).aspx.

Użycie snippetu jest absolutnie trywialne. Każdy snippet posiada swoje słowo skrótu, które pozwala wywołać snippet po wpisaniu zaledwie kilku znaków. Po wstukaniu owego skrótu wciskamy dwukrotnie tabulator. Spowoduje to wstawienie całego kodu snippeta do naszego kodu w miejsce kursora. Inne opcje to użycie skrótu klawiszowego Ctrl+K, Ctrl+X lub Ctrl+K, Ctrl+S (odpowiednio: wstawianie w miejscu kursora, otaczanie zaznaczenia ? o tym za chwilkę). Ale to jeszcze nie koniec. Połowa magii snippetu polega na szybkim jego uzupełnianiu. Po wstawieniu kodu snippetu, wybrane jego części są edytowalne. Pozwala to na proste i szybkie uzupełnienie elementów kodu jak na przykład typ wstawianego obiektu czy jego nazwa. Przechodzenie pomiędzy polami do uzupełnienia wykonuje się za pomocą tabulatora. Po uzupełnieniu snippetu wystarczy wcisnąć enter albo zacząć pisać poza snippetem co spowoduje koniec jego edycji.

Warto jeszcze wspomnieć, na koniec teorii, że są dwa rodzaje snippetów: wstawiające kod we wskazanym miejscu oraz otaczające sobą wskazany kod. Są też snippety, które mogą pracować w obu trybach. Co ciekawe, przejrzałem listę wbudowanych snippetów dla C# i żaden z nich nie służył tylko do otaczania ? każdy można było również wstawić w miejscu kursora. Przykładem snippetu tylko do wstawiania w miejscu jest snippet tworzący domyślny konstruktor w klasie. Natomiast snippety pętli można użyć do wstawienia nowej pętli w kod albo otoczenia istniejącego kodu pętlą.

Visual Studio 2010 jest na tyle sprytnym narzędziem, że monitoruje katalogi ze snippetami. Dodanie, usunięcie czy modyfikacja pliku ze snippetem (tj. pliku z rozszerzeniem .snippet) zostaną od razu zauważone i uwzględnione w środowisku. Oryginalne snippety znajdują się w katalog_instalacyjny_vs\język_programowania\Snippets, natomiast snippety użytkownika należy umieszczać w Dokumenty\Visual Studio 2010\Code Snippets. Aby ułatwić zarządzanie snippetami, Visual Studio posiada Code Snippets Manager. Znaleźć go można w menu Tools oraz pod kombinacją klawiszy Ctrl+K, Ctrl+B.

blogentry-7427-1334526218.png

Narzędzie jest całkiem proste. Pozwala przeglądać snippety dla każdego z obsługiwanych języków (wybór w combo), przyciski Add oraz Remove służą do dodawania I usuwania katalogów, w których VS szuka snippetów, a przycisk Import kopiuje snippet ze wskazanego miejsca do wybranego katalogu snippetów.

Zobaczmy, co fajnego ma Visual Studio ?out of the box? w kwestii snippetów. Nie będę wyliczał wszystkich, bo to może zrobić sobie każdy za pomocą wspomnianego przed chwilą okienka Code Snippets Managera, wymienię natomiast te, z których sam ostatnio często korzystam. Nim zacznę wyliczankę powiem, że niektóre snippety mogą wydawać się śmieszne, bo wstawiają 3 słowa i dwie klamry ? coś, co można ekspresowo wpisać. Jednak dla mnie wygodniej jest po prostu pacnąć 2 razy w tabulator niż pisać całość z palca i dlatego z nich korzystam.

  • #region ? wstawia początek i koniec regionu oraz pozwala na szybkie uzupełnienie nazwy. Prawdę mówiąc, ten snippet mnie nie do końca zadowalał, więc napisałem własny ? o tym później.
  • class ? tworzy pustą klasę o zadanej nazwie.
  • ctor ? tworzy domyślny konstruktor bieżącej klasy.
  • if oraz else ? tworzą bloki kodu warunkowego (z klamerkami).
  • do, while, for, foreach ? szablony pętli z wygodnym uzupełnieniem warunku przerwania pętli.
  • switch ? bardzo wygodny snippet, szczególnie jeśli argumentem jest obiekt typu wyliczeniowego (enum). W takim wypadku snippet wstawia od razu kod dla wszystkich możliwości danego wyliczenia.
  • prop, propfull ? dodają uzupełnialną właściwość. Pierwszy snippet dodaje automatyczną właściwość natomiast drugi wstawia też pole stojące za właściwością (backing field) na modłę .NET 2.0.
  • try oraz tryf wstawiają kod obsługi wyjątku try-catch oraz try-catch-finally.

Chwilę wcześniej wspomniałem, że domyślny #region mnie nie zadowala. Poniżej znajduje się kod oryginalnego snippetu region. Poszerzyłem go o komentarze do każdego elementu, wyjaśniające poszczególne fragmenty kodu.

CODE
<?xml version="1.0" encoding="utf-8" ?>

<!-- Główny element, który jest kontenerem na snippety, a co za tym idzie,

w jednym pliku można zdefiniować wiele snippetów.-->

<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">

<!-- Definicja pojedynczego snippetu. -->

<CodeSnippet Format="1.0.0">

<!-- Sekcja nagłówkowa -->

<Header>

<!-- Tytuł. -->

<Title>#region</Title>

<!-- Skrót tekstowy jakiego trzeba użyć w Visual Studio aby wywołać snippet. -->

<Shortcut>#region</Shortcut>

<!-- Opis. -->

<Description>Code snippet for #region</Description>

<!-- Autor. -->

<Author>Microsoft Corporation</Author>

<!-- Kolekcja trybów działania snippetu. -->

<SnippetTypes>

<!-- Snippet może być wstawiany w bieżącej pozycji kursora. -->

<SnippetType>Expansion</SnippetType>

<!-- Snippet może otoczyć zaznaczony tekst swoim kodem,

albo inaczej, zaznaczony kod może zostać użyty w treści

wstawianego przez snippet kodu. -->

<SnippetType>SurroundsWith</SnippetType>

</SnippetTypes>

</Header>

<!-- Tu znajduje się właściwe ciało snippetu. -->

<Snippet>

<!-- Deklaracje używane są do tworzenia zmiennych, które użytkownik

edytuje w trakcie wstawiania snippetu. -->

<Declarations>

<!-- Zmienna tekstowa. Poza Literal jest jeszcze Object. -->

<Literal>

<!-- Nazwa zmiennej. -->

<ID>name</ID>

<!-- Podpowiedź wyświetlana przy wpisywaniu. -->

<ToolTip>Region name</ToolTip>

<!-- Domyślna wartość. -->

<Default>MyRegion</Default>

</Literal>

</Declarations>

<!-- Dokładny kod wstawiany w edytowanym pliku. Language określa język,

dla którego snippet jest przeznaczony. Znacznik CDATA mówi parserowi XML,

że wewnątrz znajduje się fragment, którego nie należy parsować. Dlatego wszystko,

co znajdzie się wewnątrz, zostanie wklejone "żywcem".

Wyjątkiem są zmienne, które zostały zadeklarowane w sekcji Declarations,

a poniżej są otoczone znakami dolara.

Poza zdefiniowanymi zmiennymi, są też zmienne specjalne. Zmienna "selected"

określa tekst, który był zaznaczony w chwili wstawienia snippeta. Druga

specjalna zmienna to "end", która mówi, w jakim miejscu ustawić kursor po

zakończeniu edycji. Jest to całkiem wygodne.

-->

<Code Language="csharp">

<![CDATA[#region $name$

$selected$ $end$

#endregion

]]>

</Code>

</Snippet>

</CodeSnippet>

</CodeSnippets>

Często zdarza się, że region obejmuje większe partie kodu. W takich wypadkach zazwyczaj nie wiadomo, końcówkę jakiego regionu oglądamy. Istnieją różne dodatki, które to ułatwiają (np. VSCommands czy płatny CodeMap), ale przecież nie każdy musi takie dodatki posiadać. Dlatego wygodne jest, jeśli region posiada nazwę również na swoim końcu. Aby nie musieć robić tego ręcznie, modyfikujemy delikatnie oryginalny snippet ? zmieniamy tylko sekcję ?Code?. Wyglądać będzie ona tak:

CODE
<Code Language="csharp">

<![CDATA[#region $name$

$selected$$end$

#endregion $name$

]]>

</Code>

Jak widać, teraz nazwa region pojawi się automatycznie na początku oraz na końcu regionu. Dodatkowo wstawiłem puste linie pomiędzy liniami regionu, a zaznaczonym tekstem. Moim zdaniem poprawia to odrobinę czytelność kodu.

Jako drugi przedstawię banalny snippet, który zdecydowanie przyspieszał tworzenie kodu w jednym z projektów, w którym uczestniczę od dłuższego czasu. W projekcie owym przyjęte jest, że w na pewnych warstwach metody zwracają informację Sukces/Błąd, natomiast szczegółowe informacje o błędach przechowywane są w osobnej kolekcji zwanej MessageManager. W warstwie prezentacji (odsyłam do wpisu Tworzymy stronę www w ASP.NET cz.1) obsługa rezultatu najczęściej sprowadzała się do: ?jeśli błąd, to wyświetl detale błędów, a jeśli OK, to zrób coś innego?. Ponieważ ten kod powtarzał się wielokrotnie, stworzyłem taki oto snippet (pominę tu nieistotną część opisową):

CODE
<Snippet>

<Declarations>

</Declarations>

<Code Language="csharp">

<![CDATA[if(returnCode == BLReturnCode.Ok)

{

$end$

}

else

{

_viewLayer.ShowAllMessages(MessageManager);

}

]]>

</Code>

</Snippet>

Jak widać, snippet nie zawiera żadnych deklaracji zmiennych, a jedynie używa zmiennej ?end? przenosząc kursor od razu w miejsce, gdzie należy obsłużyć sukces wywołanej wcześniej operacji. Nawiasem mówiąc, znaczniki ?Declarations? można usunąć, skoro są puste.

Jako ostatni przedstawię snippet będący rozszerzeniem snippetu ?propfull?, który wstawia właściwość razem z polem stojącym za tą właściwością. Pisząc aplikację w Silverlight z wykorzystaniem wzorca MVVM (polecam wpis Tworzymy stronę www w ASP.NET cz.1,5 - interfejs Silverlight), bardzo często musiałem dodawać właściwości, które będą pełnymi właściwościami, a nie automatycznymi. Była to konieczność, ponieważ w setterze właściwości konieczne było uruchomienie zdarzenia PropertyChanged, które z kolei sygnalizuje mechanizmowi Silverlightowemu, że należy odświeżyć wiązania kontrolek z daną właściwością. Aby uprościć sobie życie, zdarzenie było uruchamiane przez metodę OnPropertyChanged(string nazwaProperty). W praktyce taka właściwość wyglądała tak:

CODE
/// <summary>

/// Name.

/// </summary>

private int _name;

/// <summary>

/// Name.

/// </summary>

public int Name

{

get 

return _name;

}

set 

_name = value;

OnPropertyChanged("Name");

}

}

Można takie coś pisać raz, dwa czy dziesięć, ale jeśli jest tego kilkadziesiąt, to snippet jest bardzo, bardzo użytecznym rozwiązaniem. Spójrzmy na kod:

CODE
<?xml version="1.0" encoding="utf-8" ?>

<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">

<CodeSnippet Format="1.0.0">

<Header>

<Title>propfullopc</Title>

<Shortcut>propfullopc</Shortcut>

<Description>Code snippet for property, backing field and OnPropertyChanged</Description>

<SnippetTypes>

<SnippetType>Expansion</SnippetType>

</SnippetTypes>

</Header>

<Snippet>

<Declarations>

<Literal>

<ID>description</ID>

<ToolTip>Description</ToolTip>

<Default>Description.</Default>

</Literal>

<Literal>

<ID>type</ID>

<ToolTip>Property type</ToolTip>

<Default>int</Default>

</Literal>

<Literal>

<ID>property</ID>

<ToolTip>Property name</ToolTip>

<Default>MyProperty</Default>

</Literal>

<Literal>

<ID>field</ID>

<ToolTip>The variable backing this property</ToolTip>

<Default>myVar</Default>

</Literal>

</Declarations>

<Code Language="csharp">

<![CDATA[/// <summary>

/// $description$

/// </summary>

private $type$ $field$;

/// <summary>

/// $description$

/// </summary>

public $type$ $property$

{

get 

return $field$;

}

set 

$field$ = value;

OnPropertyChanged("$property$");

}

}

$end$

]]>

</Code>

</Snippet>

</CodeSnippet>

</CodeSnippets>

Nie ma tu nic odkrywczego. Użytkownik podaje opis właściwości, jej typ, nazwę oraz nazwę pola. Proste, a jednocześnie bardzo wygodne.

Na dziś to tyle. Gorąco zachęcam do zapoznania się z dokładnym opisem snippetów na stronach MSDN (link w treści) ponieważ ten wpis nie obejmuje wszystkiego, jednak jest raczej wystarczający aby każdy mógł zacząć tworzyć własne, proste snippety.

Dzięki za przeczytanie i do następnego wpisu!

7 komentarzy


Rekomendowane komentarze

Ja sobie także to gdzieś zapiszę z podobnych względów. W tej chwili nie mam siły, by to przeczytać ze zrozumieniem, ale w czwartek siądę sensowniej.

Link do komentarza
Gość
Dodaj komentarz...

×   Wklejony jako tekst z formatowaniem.   Wklej jako zwykły tekst

  Maksymalna ilość emotikon wynosi 75.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...