Klávesové zkratky na tomto webu - rozšířené Na obsah stránky

Závidí nám vimaři a emacsové build na dvě kliknutí?

10.58 - 30. srpna 2008 | ASP.NET 2.0

Často se v diskusích/flamech o vývoji v Atlasu dočítám, že jsme byli blbý klikači, co se neobejdou bez wizárdů a podobných věcí. Jak je to tedy?

Pravdou je, že jsem velice poholdný až líný a nemám rád zbytečnej oser s příkazovou řádkou. Ne že bych jí nepoužíval, hodně úkolů se dá rychle zvládnout právě z ní, ale přece jen kompilace z Visual Studia na dvě kliknutí nebo spouštění build scriptu z příkazovky je dost o něčem jiném.

Nejen že na dvě kliknutí provedu build ale provedou se mi unit testy nebo vzdálený předtestovaný build a případě úspěchu i commit do repository. Upřímně písmenkáři, kdo z vás to má?

PS. Vím, že jde buildit i na jedno kliknutí nebo přes klávesovou zkratku, ale já mám rád kontextovou nabídku ;)

Autor: Aleš Roubíček | 7x komentováno | del.icio.us | Linkuj!

Binsor – síla konfigurace

15.18 - 25. srpna 2008 | ASP.NET 2.0

Pokud se dostanete do stádia, kdy potřebujete takovou architekturu, kde je potřeba používat plug-iny třetí strany, kde je potřeba snadno vyměnit komponentu za jinou, přichází ke slovu nějaký druh konfigurace.

Velice často se můžeme setkat s konfigurací komponent v XML. Ať už je to Provider pattern známý z ASP.NET, či vlastní konfigurační sekce, nebo konfigurace Windsor kontejneru, pořád tu máme XML. Jeho ohromnou výhodou je, že se dají systémové komponenty snadno překonfigurovat bez nutnosti celý systém překompilovat. Stačí pouhý restart aplikace. Navíc nástrojů na editaci a validaci XML máme nepočítaně, takže změnu konfigurace zvládne téměř každý.

Velkou nevýhodou XML, je jeho omezené výrazivo. Špatně se v něm píše foreach nebo if. Prostě na složitější konstrukce je potřeba programovací jazyk. A nebo skriptovací!

Boo na scénu

Boo je staticky typovaný objektový jazyk nad CLI (dot net) inspirovaný syntaxí Pythonu. Jeho hlavní silou je metaprogramování. Na úrovni kompilátoru se snadno dají psát makra. Takových maker lze využít k tvorbě přehledných DSL a jednou z takových je i Binsor.

Windsor + Boo = Binsor

Windsor je IoC kontejner na platformě dot net a je součástí opensource projektu Castle. Windsor má v základu dvě možnosti jak konfigurovat komponenty.

  1. Programově na úrovni mikrokernelu.
  2. XML konfigurací.

XML konfigurace je nejčastěji užívanou možností, kvůli výše popsaným výhodám. V trunku se nedávnou objevila i konfigurace pomocí DSL na principu fluent interface přímo v C#. Taková konfigurace je velice pěkná, ale je tu pořád nutnost při každé změně znova celý projekt kompilovat. Proto je tu Binsor, který si bere sílu programovacího jazyka, efektnost XML konfigurace a navíc jednoduchost a přímočarost syntaxe.

Konfigurace komponent

Nejčastější aktivitou s Binsorem nejspíš bude registrace komponent. :)

component 'my_component', IServiceContract, ServiceImplementation:
    # nastavime parametr konstruktoru
    constructorParameter = 10
    # nastavime vlastnost sluzby
    SomeProperty = "Hello Word!"

Kód je v celku jednoduchý. Na prvním řádku začínamé klíčovým slovem component, které říká, že registrujeme komponentu. Prvním parametrem je název komponenty, přes který se na ní můžeme odkazovat. Druhý parametr je rozhranní služby a třetí je konkrétní implementace, která bude při rozpoznání kontejnerem vrácena, např. IoC.Container.Resolve<IServiceContract>(). Za dvojtečkou pokračuje výčet nastavovaných vlastností a parametrů. Můžeme takto nastavovat i speciální vlastnost ovlivňující životnost objektu.

component HttpRequest:
    lifestyle Singleton

Všimněte si, že se ani nemusí při registraci uvádět referenční název nebo abstraktní typ. Může se klidně rovnou registrovat typ konkrétní, který se bude v tomto případě chovat jako singleton. Takovéto ukázky jsou fešné, ale nic, co bychom nezvládli pomocí XML. Pojďme trochu dál.

for type in AllTypesBased of Controller("MyApplication.Web"):
    component type

Tento kód zaregistruje všechny controllery (třídy, které jsou potomky třídy Controller) z assembly MyApplication.Web. Krom generické metody AllTypesBased, je tu ještě generická metoda AllTypesWithAttribute a negenerická AllTypes. Všechny mají jako parametr název assembly, jejíž typy procházejí.

Facility

Neméně důležitou součástí konfigurace jsou facility, které dodávají kontejneru nové možnosti a zapouzdřují větší sady komponent do logických jednotek. Pro ukázku konfigurace ActiveRecord komponent pomocí Binsoru:

facility ActiveRecordFacility:
    configuration:
        @isWeb = true, isDebug = true
        assemblies = [ Assembly.Load("MyApplication.Entities") ]
        config(keyvalues, item: add):
            show_sql = true
            command_timeout = 5000
            cache.foo.use_query_cache = false
            dialect = 'NHibernate.Dialect.MsSql2005Dialect'
            connection.provider = 'NHibernate.Connection.DriverConnectionProvider'
            connection.driver_class = 'NHibernate.Driver.SqlClientDriver'
            connection.connection_string = 'connectionString1'

Shrnutí

Osobně se mi možnosti konfigurace přes Binsor velice líbí, ale je celkem možné, že ne každému tu může vyhovovat. Pokud ale používáte Windsor a přijde vám XML konfigurace nepřehledná, je toto možná cesta, jak z toho ven. Pokud chcete nějaké lepší příklady, doporučuju si stáhnout SVN repository https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/rhino-commons a projít si testy. Jako editor se mi osvědčil SharpDevelop, který má podporu pro Boo přímo v základu, nebo doinstalovat BooLang Studio do Visual Studia.

Autor: Aleš Roubíček | 2x komentováno | del.icio.us | Linkuj!

NForms na Codeplexu

13.59 - 16. srpna 2008 | ASP.NET 2.0

Na Codeplexu se objevil nový opensource projekt a není to nic menšího než NForms. Zatím jste se o nich mohli jen dočíst u mě na blogu a prakticky vyzkoušet taktéž tady – přidávání komentářů frčí na NForms. Nyní však máte jedinečnou možnost stáhnout si zdrojáky, poučit se z nich, nahlásit chyby nebo diskutovat náměty na vylepšení, zkompilovat, spustit testy a konečně nasadit a používat ve vlastních projektech.

No není to skvělé?

K čemu je to dobré?

NForm jsem napsal jako programátorské cvičení. Líbila se mi Davidova myšlenka, chtěl jsem napsat něco v C# 3.0… Jenže je to taky docela užitečná věc. Daj se pomocí toho snadno vytvářet znovupoužitelné formuláře nezávislé na infrastruktuře. Můžete je používat jak v klasickém ASP.NET modelu (můžete použít více než jeden formulář na stránce), tak v MVC nebo MVP modelu.

Další vývoj

Aktuálně připravuju podrobnější dokumentaci na wiki, ale pro začátek jistě bude stačit pár mých spotíků tady na blogu, příklady užití najdete v Unit Testech, popřípadě další moudra najdete v nedokonalých XML komentářích v samotném kódu.

Při psaní wiki jsem už našel nějaké možnosti pro vylepšení, tak až bude připraveno, hodím je zase na Codeplex. Stay tuned…

Časem bych chtěl přidat podporu validace na straně klienta. Zatím se generují jen některé třídy, na které lze napojit vlastní implementace v JavaScriptu, ale není to nic pro složitější validaci…

Credits

Musím poděkovat Davidovi za inspiraci, NForms jsou značně obšlehnuté od Nette::Forms (dříve známé jako NForms), trochu inspirace jsem pobral i u New Forms z djanga, některé zajímavé nápady, jak využít novinky C# 3.0 pro změnu z ASP.NET MVC. Takže díky!

Autor: Aleš Roubíček | 2x komentováno | del.icio.us | Linkuj!

Testování HttpContextu

13.56 - 25. července 2008 | ASP.NET 2.0

Píšu nějaké podpůrné třídy pro naše nové projekty a zrovna jsem u utilitek pro webové aplikace. Teď jsem se dostal k jedné třídě, která volá HttpContext.Current ve statických metodách. Chci na to napsat testy, jenže jak mám podstrčit HttpContext?

Řešení je nakonec jednodušší než jsem čekal…

public static void CreateContext() {
  CallContext.HostContext = new HttpContext(
    new HttpRequest("default.aspx", "http://rarous.net/", "test1=test"),
    new HttpResponse(new StringWriter())
  );
}

Stačí zavolat tuto metodu, kterou se do threadu nastaví podvržený kontext a můžete směle testovat. :)

Autor: Aleš Roubíček | Zatím bez komentáře | del.icio.us | Linkuj!

Důvěryhodná síťová cesta

14.00 - 23. července 2008 | ASP.NET 2.0

Společné knihovny v našich projektech linkujeme z jednoho síťového místa. Při spouštění testů z Visuál Studia se v tomto případě může objevit chybová hláška, že knihovna není v důvěryhodném umístění a testy se nepodaří spustit.

Microsoft.VisualStudio.TestTools.TestManagement.ExecutionException: Test Run deployment issue: The location of the file or directory ‘\\server\path\library.dll’ is not trusted.

Existuje na to celkem snadné řešení, ale je poměrně těžko dohledatelné… Je potřeba toto umístění přidat mezi důvěryhodná uložiště assembly .net Frameworku. Nejsnažší cesta je nastavit CAS Policy asi přes příkazovou řádku:

cd %SystemRoot%\Microsoft.NET\Framework\v2.0.50727
caspol -m -ag 1.2 -url \\Server\path\* FullTrust

Snad se bude hodit.

Autor: Aleš Roubíček | Zatím bez komentáře | del.icio.us | Linkuj!

Generický kontejner a repeater

11.55 - 31. května 2008 | ASP.NET 2.0

Zrovna předevčírem jsem měl v plánu napsat tenhle článek, ráno jsem si napsal ukázkovou třídu, kterou najdete níže, a pak šel do práce. Připravoval jsem dva celkem důležité stagingy a nakonec ještě ta Havana Party. No, a když jsem se vrátil z nákupu, zastihl jsem přímý přenos ze spouštění La Trine. A bylo po článku. Teda jen dočasně, protože i včera jsem měl nějakou snahu, tak jsem napsal první půlku článku.

Někdy před rokem jsem publikoval ukázku, jak si vytvořit vlastní kontrol s Layout Template. Před pár týdny zase pomocníka na vyhledávání komponent ve stránce i mimo jmenný kontejner. To jsou takoví pomocníci, kteří mi usnadňují tvorbu serverových ovládacích prvků. A dneska si ukážeme jejich dalšího bratříčka – generický kontejner.

Kontejner

Kontenery se používají u šablonovaných prvků svázaných s daty. Slouží jako držitel dat pro konkrétní instanci šablony. Jistě jste se setkali s Evalováním, když jste prováděli databinding. Problém je v tom, že s sebou přináší značnou režii spojenou s boxingem. Výhodnější je používat plně typový kontejner. Zvýšíte tím nejen výkon stránky, ale i zístkáte vyšší komfort v podobě Intellisense v šabloně.

Já jako základ takových kontejnerů používám generický kontejner, který má následující rozhraní.

public interface IGenericConteiner<T> : INamingContainer {
  T DataItem { get; }
}

Toto rozhraní pak implementuju následovně:

public class GenericContainer<T> : Control, IGenericContainer<T> {
  public GenericContainer<T>(T dataItem) {
    DataItem = dataItem;
  }
  public T DataItem { get; priváte set; }
}

Dalším vhodným kontejnerem je prázdný kontejner:

public class EmptyContainer : Control, INamingContainer {
}

S těmito kontejnery se dá pokrýt obrovské množství potřeb. Jak je využít v praxi si ukážeme v následující čás­ti.

Generický repeater

Nyní vezmu kostičky naší stavebnice a postavím z nich základ pro vypisovače silně typových dat.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Rarous.Web.UI {
  [ParseChildren(true)]
  public abstract class GenericRepeaterBase<T> : CompositeControl, ILayoutTemplateable {

    protected bool isBound;

    public IEnumerable<T> DataItem { get; set; }

    public abstract ITemplate ItemTemplate { get; set; }

    public abstract ITemplate AlternatingItemTemplate { get; set; }

    [DefaultValue(typeof(ITemplate), "")]
    [PersistenceMode(PersistenceMode.InnerProperty)]
    [TemplateContainer(typeof(INamingContainer))]
    [TemplateInstance(TemplateInstance.Multiple)]
    public ITemplate SeparatorTemplate { get; set; }
    #region ILayoutTemplateable Members
    [PersistenceMode(PersistenceMode.Attribute)]
    public string LayoutContainerId { get; set; }

    [DefaultValue(typeof(ITemplate), "")]
    [PersistenceMode(PersistenceMode.InnerProperty)]
    [TemplateContainer(typeof(INamingContainer))]
    [TemplateInstance(TemplateInstance.Single)]
    public ITemplate LayoutTemplate { get; set; }
    #endregion
    #region CompositeControl Members
    protected override void CreateChildControls() {
      Control container = TemplatingHelper.CreateLayoutContainer(this, this);

      bool alternate = false;
      foreach (T item in DataItem) {
        ITemplate template = alternate ? AlternatingItemTemplate ?? ItemTemplate : ItemTemplate;
        TemplatingHelper.Instantiate(new GenericContainer<T>(item), template, container);
        TemplatingHelper.Instantiate(new EmptyContainer(), SeparatorTemplate, container);
        alternate = !alternate;
      }
    }
    public override void DataBind() {
        base.DataBind();
        isBound = true;
    }
    protected override void OnInit(EventArgs e) {
      EnableViewState = false;
      base.OnInit(e);
    }
    protected override void OnPreRender(EventArgs e) {
      if (isBound == false) {
        DataBind();
      }
      base.OnPreRender(e);
    }
    protected override void Render(HtmlTextWriter writer) {
      base.RenderContents(writer);
    }
    #endregion
  }
}

Na takovémto základě se dá stavět už slušná řada konkrétních ovládacích prvků, kde už jen doplníme šablonový typ a můžeme přidat další vlastnosti dle potřeby.

V ukázce si můžete povšimnout, že jako typ kontejneru šablony uvádím pouze rozhraní. Dělám to kvůli zpřehlednění IntelliSense. Když pak používám výraz pro svázání s daty v šabloně, dostanu pouze vlastnosti a metody kontejneru, které jsou definovány rozhraním, nikoli spoustu zbytečných vlastností a metod, které sebou nese třída Control ze které musí být kontejner poděděný.

Doufám, že se bude hodit a pokud najdete nějakou chybu, neváhejte a reportujte :)

Autor: Aleš Roubíček | Zatím bez komentáře | del.icio.us | Linkuj!

Chybka se vloudila

12.59 - 26. května 2008 | ASP.NET 2.0

V kódu, který jsem publikoval před nedávnem v článku Vyhledávání komponent v ASP.NET stránce, se vyskytla chyba. Za její odhalení děkuju Martinovi Davidovi (DaMa). Opravený kód jsem přepublikoval.

V čem byla chyba?

Mylně jsem se domníval, že všechny NamingContainery implementují rozhraní INamingContainer. Jenže je tu drobná past. HtmlForm, základní kámen WebForms, toto rozhraní neimplementuje a přesto slouží jako bariéra v rekurzivním prohledávání. Řešením nakonec bylo přidání do podmínky, kde kontroluju implementaci INamingContaineru i kontrolu na HtmlContainerControl. To je vše.

Autor: Aleš Roubíček | 1x komentováno | del.icio.us | Linkuj!

Active Record vs. Repository pattern

12.38 - 21. května 2008 | ASP.NET 2.0

Dnes se podíváme na dva návrhové vzory z oblasti přístupu k datům, které používají zcela odlišnou filosofii, ale nakonec si ukážeme, že jejich kombinací, můžeme získat celkem zajímavé výsledky.

Active Record

Návrhový vzor Active Record staví na předpokladu, že základem aplikace je databázový model a od něj se vše odvíjí. Každý řádek tabulky je reprezentován konkrétní instancí objektu. Většinou je takový objekt odvozen od bázové třídy, která implementuje potřebné rozhranní pro persistenci objektu – typicky CRUD metody.

Diagram vzoru ActiveRecord

Tento vzor se hojně využívá v různých ORM frameworcích. Je součástí dnes velmi módních frameworků Ruby on Rails, django nebo Castle, které na něm stavějí svůj datový model a díky velice snadnému mapování dokážete napsat (vygenerovat) kostru databázové aplikace během několika málo minut.

Pro velice jednoduché aplikace může být tento vzor, díky své jednoduchosti, vhodný. Jenže porušuje několik pravidel dobrého objektového návrhu (persistence ignorance, single responsibility, pevně daná bázová třída, atd.).

Repository

Návrhový vzor Repository je základním kamenem doménou řízeného návrhu. Model aplikace nemá ponětí o tom, jakým způsobem je persistován. O to se stará právě Repository. Navíc díky tomu, že se o persistenci stará cizí objekt, stačí nám znát pouze jeho rozhranní a v případě potřeby ho snadno nahradit jiným.

Diagram vzoru Repository

Kombinace

Teď zabrousím do konkrétnějších implementací a to do ActiveRecord z projektu Castle. Tako konkrétní implementace je postavená na běhovém prostření dotnet a jako svůj základ používá ORM nástroj NHibernate.

Nejpřímější cesta jak s ním pracovat, je podědit třídu z bázové třídy ActiveRecordBase a označit ji a její vlastnosti patřičnými atributy:

[ActiveRecord]
public class User : ActiveRecordBase<User> {
  [PrimaryKey] public int Id { get; set; }
  [Property] public string Name { get; set; }
  [Property] public string Email { get; set; }
  [Property] public string Login { get; set; }
  [Property] public string Password { get; set; }
}

A můžeme pracovat. Autoři si však byli vědomi toho, že vzor Active Record nemusí vyhovovat všem a přidali statickou třídu ActiveRecordMediator, který dokáže posloužit jako základ pro Repository. Třída pak nemusí dědit z ActiveRecordBase:

[ActiveRecord]
public class User {
  [PrimaryKey] public int Id { get; set; }
  [Property] public string Name { get; set; }
  [Property] public string Email { get; set; }
  [Property] public string Login { get; set; }
  [Property] public string Password { get; set; }
}

public class UsersRepository : IRepository<User> {
  public User Load(int id) {
    return ActiveRecordMediator<User>.FindByPrimaryKey(id);
  }
  public void Save(User obj) {
    ActiveRecordMediator<User>.Save(obj);
  }
  public void Delete(User  obj) {
    ActiveRecordMediator<User>.Delete(obj);
  }
}

To už je o něco lepší, ale stále máme v aplikačním modelu silnou vazbu na datový model. Můžeme se posunout o level dál a zkombinovat oba vzory tak, abychom z nich vytěžili co nejvíce. Základní myšlenkou je to, že v aplikaci budeme mít jak datový model, tak doménový. Datový model se bude pomocí Active Record starat o persistenci a Repository poslouží k transformaci doménového modelu na ten datový.

Něco podobného můžete najít v seriálu, který píše Rob Conery, kde používá zjednodušenou Repository, IQueryable jako filtry a LINQ2SQL jako datový model. Velice zajímavé, doporučuji ke shlédnutí.

Tagy: , ,

Autor: Aleš Roubíček | 2x komentováno | del.icio.us | Linkuj!

Vyhledávání komponent v ASP.NET stránce

13.13 - 2. května 2008 | ASP.NET 2.0

Asi málo koho překvapí, že v ASP.NET jsou komponenty, ze kterých se skládá výsledná stránka. Někdy však narazíme na potřebu provázat tyto prvky mezi sebou. Jednou z možností je vyhledávání přes ID prvku.

Vývojáři na toto pamatovali a každý potomek třídy System.Web.UI.Control má metodu FindControl(string), která rekurzivně projde strom potomků a snaží se najít toho se zadaným ID. To je všechno moc hezký, jenže je tu jeden háček, který to tak trochu celý nabourává.

Rekurzivně se prohledává pouze v rozsahu jmenného kontejneru. Pokud je mezi potomky komponenta implementující rozhranní System.Web.UI.INamingContainer, jeho potomci se neprohledávají. Pak přijdeme na problém, kdy chceme na celé stránce najít komponentu s daným ID. Pokud stránka obsahuje WebForm, nebo je to ContentPage, nebo má šablonované prvky, ve kterých je hledaná komponenta zanořená, tak zavolání Page.FindControl("HledaneID") vrátí null.

Řešení problému

Kdysi jsem si napsal pomocníka. Který ošetřoval různé podmínky (MasterPage, WebForm a ContentPlaceHol­dery). Byl dost konkrétní, ale na většinu případů užití bohatě stačil. Ta funkce nebyla moc hezká. Nedávno jsem narazil právě na popis toho, proč mi to kdysi nefungovalo a musel jsem psát ty výjimky, který jsem snad osvětlil v předchozím odstavci. Nová upravená verze vypadá následovně:

using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;
using System.Web.UI.HtmlControls;

public class PageHelper {
  /// <summary>
  /// Najde ovládací prvek požadovaneho typu na strance
  /// včetně ošetření na MasterPage.
  /// </summary>
  /// <typeparam name="T">Typ ovládacího prvku.</typeparam>
  /// <param name="parent">Ve které stránce se má hledat.</param>
  /// <param name="controlID">ID Controlu ve stránce.</param>
  /// <returns></returns>
  public static T FindControl<T>(Page parent, string controlID)
    where T : Control {
    return FindControl(parent.Master as Control ?? parent as Control, controlID) as T;
  }

  private static Control FindControl(Control parent, string controlID) {
    if (parent == null) {
      throw new ArgumentNullException("parent");
    }
    if (String.IsNullOrEmpty(controlID)) {
      return null;
    }

    Control result = parent.FindControl(controlID);
    if (result == null && parent.Controls.Count > 1) {
      foreach (Control child in parent.Controls) {
        if (child is INamingContainer || child is HtmlContainerControl) {
          result = FindControl(child, controlID);
        }
        if (result != null) {
          break;
        }
      }
    }
    return result;
  }
}

Snad se bude hodit.

Související

Tagy: , , [tag-findcontrol]

Autor: Aleš Roubíček | Zatím bez komentáře | del.icio.us | Linkuj!

Using pattern

15.32 - 14. dubna 2008 | ASP.NET 2.0

Je tomu již dlouhá doba, co jsem psal spotík o užívání bloku using v jazyce C# pro třídy implementující rozhranní System.IDisposable. Tohoto bloku se dá využít k logickému členění kódu do bloků a vytvořit tak syntax sugar na úrovni API.

Ukázky užití

S using patternem se v moderních API dá potkat celkem často. První ukázka je z mockovacího frameworku Rhino Mocks. Používá se pro nahrávání a přehrávání chování mockovaného objektu.

MockRepository mocks = new MockRepository();
IDependency dependency = mocks.CreateMock<IDependency>();

using(mocks.Record()) {
    Expect.Call(dependency.GetSomething("parameter")).Return("result");
    dependency.DoSomething();
}

using(mocks.Playback()) {
    Subject subject = new Subject(dependency);
    subject.DoWork();
}

Using pattern usnadňuje čtení takovéhoto kódu a hned je jasná i logická struktura.

Další ukázka pochází z ASP.NET MVC frameworku, kde se using pattern používá v HTML helperu pro generování formuláře.

<% using(Html.Form<HomeController>(action => action.Index())) { %>
...
<% } %>

Implementace

Základem, tedy, je blok using, který slouží k bezpečnému zavolání metody Dispose objektu implementujícího rozhranní System.IDisposable. Jak na to, když v using bloku předáváme metodu a ne objekt? Jednoduše, musíme vrátit v metodě objekt, který se o špinavou práci postará. V podstatě ani nemusí být nijak inteligentní.

public class UsingPattern : IDisposable {

  private WorkerMethod _method;

  public delegate void WorkerMethod();

  public UsingPattern(WorkerMethod method) {
    _method = method;
  }

  public void Dispose() {
    _method();
  }
}

Užití v našem API je pak celkem triviální.

public class SomeClass {
  public UsingPattern SomeMethod() {
    Console.WriteLine("Zacatek bloku");
    return new UsingPattern(() => Console.WriteLine("Konec bloku"));
  }
}

public class OtherClass {
  public void Consumer() {
    var some = new SomeClass();

    using (some.SomeMethod()) {
      Console.WriteLine("Blok");
    }
  }
}

Tagy: ,

Autor: Aleš Roubíček | Zatím bez komentáře | del.icio.us | Linkuj!