
Monday, September 11, 2006

Sunday, July 02, 2006
Řešení programátorské hádanky z 24.6.2006 - ThreadStartDelegate
Jak bylo patrné ze zadání "hádanky", snažil jsem se, abyste mi napsali, jaké postupy používáte pro předání argumentů a získání návratové hodnoty z metody, když jste omezeni signaturou delegátu ThreadStartDelegate. Třída Thread dokáže pracovat pouze s metodami bez návratových hodnot (void) a také:
a) Metoda nesmí mít žádné argumenty - delegát ThreadStartDelegate
b) Metody přijímající jeden argument typu object - delegát ParameterizedThreadStart (pouze v .Net Frameworku 2.0).
Jak jste se zmínili v komentářích - když chceme předat argumenty kódu vykonávanému v samostatném threadu, můžeme použít třídy s vlastním stavem a návratovou hodnotu získat třeba tak, že si zaregistrujeme "callback" funkci.
Mně by se ale líbilo, kdybych měl jen jednu "stavovou" třídu s argumenty pro metody s jakoukoli signaturou a tedy společnou pro všechny rozdílné typy delegátů a hlavně chci objekt z této třídy přímo předat do konstruktoru třídy Thread, aby se můj kód nijak nelišíl od přímého použití delegátů ThreadStart a ParameterizedThreadStart. Proto jsem v komentářích mluvil o eleganci zvoleného řešení :)
class ThreadStartDelegateWrapper
{
#region Private members
private Delegate m_innerDelegate;
private object[] m_methodParameters;
private object m_returnValue;
#endregion Private members
#region Construtors
/// <summary>
/// Konstruktor
/// </summary>
/// <param name="del">Delegát ukazující na metodu, která poběží v jiném threadu</param>
public ThreadStartDelegateWrapper(Delegate del)
{
if (del == null)
{
throw new ArgumentNullException("del");
}
m_innerDelegate= del;
}
/// <summary>
/// Konstruktor
/// </summary>
/// <param name="del">Delegát ukazující na metodu, která poběží v jiném threadu</param>
///<param name="methodParameters">Argumenty metody</param>
public ThreadStartDelegateWrapper(Delegate del, params object[] methodParameters) : this(del)
{
m_methodParameters = methodParameters;
}
#endregion Construtors
#region Public properties
/// <summary>
/// Argumenty metody
/// </summary>
public object[] MethodParameters
{
get
{
return m_methodParameters;
}
set
{
m_methodParameters = value;
}
}
/// <summary>
/// Návratová hodnota metody
/// </summary>
public object ReturnValue
{
get
{
return m_returnValue;
}
}
#endregion Public properties
#region Operators
/// <summary>
/// Implicitní konverzní operátor, který instanci třídy <see cref="ThreadStartDelegateWrapper"/> převede na delegáta <see cref="ThreadStartDelegate"/>
/// </summary>
/// <param name="originalWrapper">Instance třídy <see cref="ThreadStartDelegateWrapper"/></param>
/// <returns>Instanci delegáta <see cref="ThreadStartDelegate"/>, který ukazuje na metodu zapouzdřující zavolání jakéhokoli delegáta</returns>
public static implicit operator ThreadStart(ThreadStartDelegateWrapper originalWrapper)
{
if (originalWrapper == null)
{
throw new ArgumentNullException("originalWrapper");
}
return new ThreadStart(originalWrapper.InvokeDelegate);
}
#endregion Operators
#region private methods
//Metoda, jejíž signatura odpovídá signatuře deklarované delegátem ThreadStartDelegate
private void InvokeDelegate()
{
m_returnValue = m_innerDelegate.DynamicInvoke(m_methodParameters);
}
#endregion private methods
}
Třídě ThreadStartDelegateWrapper můžete do konstruktoru předat odkaz na jakéhokoli delegáta a také můžete předat všechny potřebné argumenty metodě, na kterou delegát ukazuje (argument methodParameters v konstruktoru). Předané argumenty můžete kdykoli upravit, protože jsou zveřejněny ve vlastnosti MethodParameters.
Abych mohl svoji třídu použít kdekoli je očekáván delegát ThreadStart, napsal jsem implicitní konverzní operátor třídy ThreadStartDelegateWrapper na delegát ThreadStartDelegate.
Návratovou hodnotu metody vykonané v jiném threadu nalezneme ve vlastnosti ReturnValue - nic nám také nebrání přidat událost, ve které získanou návratovou hodnotu budeme sami aktivně distribuovat všem zájemcům.
A tady je jednoduchý ukázkový kód.
class Test
{
public delegate string TestDelegate(string message);
public string WriteMessage(string message)
{
Console.WriteLine(message);
return "OK";
}
}
class Program
{
static void Main(string[] args)
{
Test myTestClass = new Test();
Test.TestDelegate myDelegate = myTestClass.WriteMessage;
ThreadStartDelegateWrapper wrapper = new ThreadStartDelegateWrapper(myDelegate, new object[] { "Hello world" });
Thread myThread = new Thread(wrapper);
myThread.Start();
myThread.Join();
Console.WriteLine(wrapper.ReturnValue);
Console.Read();
}
}
Je jednoduché rozšířit třídu ThreadStartDelegateWrapper o podporu dalších delegátů v .NET Frameworku (např. WaitCallback), takže na metody s různými signaturami mohou ukazovat typičtí delegáti v .Net Frameworku s využitím jedné jediné třídy fungující jako obecný adaptér mezi naším kódem a kódem v .Net Frameworku.
Sunday, July 02, 2006 2:40:08 PM (Central Europe Standard Time, UTC+01:00)
.NET Framework | Programátorské hádanky

Saturday, June 24, 2006
Programátorská hádanka - jak metodě v delegátu ThreadStart předat argumenty?
Jak asi víte, delegát ThreadStart v .Net Frameworku může ukazovat pouze na metodu, která nemá žádné argumenty a vrací void.
Jak nejlépe metodě v delegátu ThreadStart předat argumenty? A navíc - dokázali byste, aby metoda spuštěná v delegátu ThreadStart vrátila hodnotu, nebo si teď už opravdu jen vymýšlím po dobrém sobotním bourbonu nějaké rozkošné .Net 3.0 pohádky?
Napadlo mě totiž docela elegantní řešení, tak by mě zajímalo, jestli ho někdo z vás už zná a používá? 
Saturday, June 24, 2006 10:28:13 PM (Central Europe Standard Time, UTC+01:00)
.NET Framework | Programátorské hádanky

Thursday, April 27, 2006
Řešení hádanky z 18-.4. - vztahy Include, Extend v případech užití
Protože kolegové v diskuzi pod původním spotem podrobně rozebrali všechny aspekty vztahu Include a Extend v případech užití, je tento můj spot z větší části sumarizující. V čem tedy byl "chyták"? Cílem hádanky bylo upozornit na to, že vztahy Include a Extend nemusejí být tak jednoduše rozpoznatelné, jak se dočtete v různých rychlopříručkách, a také jsem chtěl, abyste si všimli, že vztah Extend bylo bylo příjemné zpřesnit tím, co sám pro sebe nazývám "anonymní datové sloty".
Tak toto byl začátek dvoustránkového spotu, který se mi podařilo omylem smazat. :-( Protože už se mi nechce teď psát celý spot znovu, tak jen v krátkosti zrekapituluji, čeho se hádanka týkala.
Specifikace UML popisuje vztahy Include a Extend takto:
"Include is a directed relationship between two use cases, implying that the behavior of the included use case is inserted into the behavior of the including use case. The including use case may only depend on the result (value) of the included use case. This value is obtained as a result of the execution of the included use case."
"This relationship specifies that the behavior of a use case may be extended by the behavior of another (usually supplementary) use case. The extension takes place at one or more specific extension points defined in the extended use case. Note, however, that the extended use case is defined independently of the extending use case and is meaningful independently of the extending use case. On the other hand, the extending use case typically defines behavior that may not necessarily be meaningful by itself. Instead, the extending use case defines a set of modular behavior increments that augment an execution of the extended use case under specific conditions. Note that the same extending use case can extend more than one use case. Furthermore, an extending use case may itself be extended."
V hádance nemohl být vztah mezi případem užití 'Založení objednávky' a 'Platba kartou' Include ani Extend. Include nelze použít, protože máme i jiné typy plateb, a případ užití Platbu kartou tedy nelze vložit povinně (dalším typem platby bude třeba dobírka - žádné záludnosti ohledně plateb jsem přichystány neměl, jen jsem chtěl, abyste se jako správní analytici pídili po podrobném zadání
). Nejedná se ale ani o vztah Extend, protože rozšířený případ užití nijak nezávisí na rozšiřujícím případu užití a nemůže číst žádné jeho "návratové hodnoty" - pro nás to znamená, že nezjistíme, jestli platba prošla.
Řešením je vytvoření nového abstraktního případu užití nazvaného třeba 'Kontrola platby', který přes vazbu Include provážeme s případem užití 'Založení objednávky' . Konkrétními potomky budou "Kontrola platby kartou", "Kontrola ostatních typů plateb". Vazba Include nám dovoluje číst návratovou hodnotu vloženého případu užití. V alternativním toku událostí případu užití 'Založení objednávky' podle vybraného typu platby vložíme konkrétní případ užití a dle výsledku vkládaného případu užití dokončíme hlavní tok událostí. Když neprojde platba kartou, můžeme zákazníkovi nabídnout výběr jiného typu platby.
Hlavně ale platí - celá hádanka i její řešení je jen hříčka bez užitku pro zákazníka, která demostruje, jak lze i méně časté vztahy řešit běžnými výrazovými prostředky jazyka UML. Stále platí, že vazby Include, Extend ani gen-spec zákazníkovi raději moc neukazujte, jestliže nechcete zbytečně trávit čas vysvětlováním vztahů, které jsou pro projekt málo podstatné a pro zákazníka samotného většinou jen iritující.
Thursday, April 27, 2006 6:25:16 PM (Central Europe Standard Time, UTC+01:00)
Programátorské hádanky | UML

Tuesday, April 18, 2006
Zajímavý dotaz (hádanka) na případy užití v UML - vztah Include, Extend, anebo ...?
Po základní analýze jste zjistili, jak zákazníci vašeho klienta vytvářejí objednávky:
"Zákazník v našem obchodě vybírá zboží a poté si může vybrat, jak jej uhradí. Jedním z možných typů platby je platba kartou. K založení objednávky dojde pouze tehdy, pokud zadané údaje o platební kartě jsou platné, zákazník má dostatečnou hotovost na účtu a platba tedy projde."
Řekněme, že z těchto údajů vytvoříme (kromě dalších, zde nezmiňovaných) dva případy užití:
- UC001 - Založení objednávky zákazníkem
- UC002 - Platba kartou
Jaký vztah je podle UML mezi těmito případy užití ? Odpověď není tak jednoduchá, jak se může na první (a dokonce i druhý a ležérní třetí) pohled zdát... 
Tuesday, April 18, 2006 9:27:39 AM (Central Europe Standard Time, UTC+01:00)
Programátorské hádanky | UML

Sunday, February 26, 2006

Saturday, July 30, 2005
Řešení hádanky "Znáte dobře návrhové vzory"
Protože nikdo nedodal kompletní řešení k hádance z 26.7., zde je odpověď.
- Třída MessageReceiverBase - událost MessageReceived, návrhový vzor Observer.
- Třída MessageReceiverBase -metoda CreateMessage, návrhový vzor Factory Method. Metoda CreateMessage vrací přímo instancí třídy Message nebo její potomky. Potomci třídy MessageReceiverBase mohou metodu přepsat a vrátit z metody například instanci OrderMessage, aniž by byly dotčeny vysokoúrovňové scénaře pracující pouze s rozhraním Message a deklarované na úrovni MessageReceiverBase.
- Třídy MessageReceivePoint, MessageReceiverBase a její potomky můžeme považovat za participanty návrhového vzoru Bridge. Třída MessageReceivePoint je abstrakcí - logickým přístupovým bodem, který dokáže přijímat data na daném URI a který interně využívá konkrétní fyzický přístupový bod, jímž je potomek třídy MessageReceiverBase zapouzdřující detaily komunikace po zvoleném přenosovém protokolu. Metoda Listen třídy MessageReceivePoint deleguje volání na metodu Listen třídy MessageReceiverBase. Samozřejmě lze o potomcích třídy MessageReceiveBase uvaživat i jako o strategiích, jak zaznělo v diskuzi o spotu, i když si myslím, že vzor Bridge lépe vyjadřuje role tříd.
- Třída AddMesageAttributesProcessor - jak vyjadřuje její název, jedná se o realizátora vzoru Content Enricher - k přijaté zprávě dodává další informace, které nebyly přímo její součástí ale které jsou důležité pro další zpracování zprávy. Příklad - messagingový systém přijme objednávku a Content Enricher ke zprávě doplní údaje o platební morálce zákazníka.
- Třída FilterMessageAttributesProcessor - opět dle názvu můžete usuzovat, že jde o návrhový vzor Content Filter. Procesor z přijaté zprávy odstraní všechny informace, které nejsou důležité pro další zpracování a které by pouze zbytečně vytěžovaly zdroje serveru. Příklad - messagingový systém přijme obrázové přílohy, které není třeba posílat k dalšímu zpracování, ale pouze se archivují v DMS, takže nemá smysl hnát obrázky celým procesem vyřizování objednávky. Content Filter obrázky ze zprávy před jejím dalším zpracováním odstraní.
Jak někteří z vás (Petr :) ) správně vytušili, diagram také svádí k tomu, aby byl rozšířen o Intercepting filter nebo o vzor Pipes&Filters - tyto vzory v něm ale v současné podobě nalezneme poze jako latentní možnosti, které můžeme uskutečnit doplněním a úpravou vztahů mezi existujícími třídami.
Saturday, July 30, 2005 5:22:25 PM (Central Europe Standard Time, UTC+01:00)
Návrhové vzory | Programátorské hádanky

Tuesday, July 26, 2005
Hádanka - znáte dobře návrhové vzory?
Dokážete na následujícím diagramu najít všechny použité návrhové vzory?
Pokud by to někomu přišlo trapně jednoduché, můžete dávat návrhy na vylepšení diagramu...
BTW: Ten diagram není z reálného projektu, takže můžete opravdu usuzovat na návrhové vzory jen podle vztahů, případně podle názvů elementů v diagramu. Je to jen hra 
Stažení diagramu
Tuesday, July 26, 2005 5:01:52 PM (Central Europe Standard Time, UTC+01:00)
Programátorské hádanky

Wednesday, March 30, 2005

Tuesday, November 09, 2004

Tuesday, October 26, 2004
Další úterý s programátorskou hádankou
Máte tento kód:
using System;
namespace Blog.Test
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class DelegateTest
{
public delegate int CallOperation (int x, int y);
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
CallOperation operation = new CallOperation(Add);
operation += new CallOperation(Substract);
int result = operation( 2, 2);
Console.WriteLine(result);
Console.Read();
}
public static int Add(int x, int y)
{
return (x + y);
}
public static int Substract(int x, int y)
{
return (x - y);
}
}
}
Otázka 1) Dokážete bez spuštění programu říct, jaký výsledek bude v proměnné result a proč?
Otázka 2) Umíte přepsat tento kód tak, abyste dostali návratové hodnoty z obou metod, na něž ukazuje kompozitní delegát?
Tuesday, October 26, 2004 6:50:00 PM (Central Europe Standard Time, UTC+01:00)
Programátorské hádanky

Tuesday, October 19, 2004
Programátorská hádanka na nudné úterý
Dokážete najít dva ekvivalentní zápisy zámku (lock) v metodě AtomicOperation?
class AtomicTest
{
private int x = 0;
private int y = 0;
public void AtomicOperation(int arg)
{
lock(this)
{
x += arg;
y += arg;
}
}
}
Tuesday, October 19, 2004 5:27:00 PM (Central Europe Standard Time, UTC+01:00)
Programátorské hádanky

Thursday, October 07, 2004
Dokážete najít všechny chyby v kódu?
Dokážete poznat všechny nesmysly v tomto kódu? Nejde o žádný reálný příklad, jen o letmé zachycení a nakupení střípků potměšilých nočních programátorských můr, jimiž je moje podvědomí neodbytně zaplavováno a mučeno po duševně drásající refaktorizaci cizího kódu...;)
using System;
using System.Collections;
namespace DirtyProject.BusinessModel
{
public class Order
{
private int m_id;
private ArrayList m_orderItems;
public Order(int id)
{
m_id = id;
LoadOrSave(false);
m_orderItems = new ArrayList();
}
public virtual void DeleteAndNotifyCustomer()
{
//Implementace
}
public virtual void LoadOrSave(bool save)
{
//implementace perzistence
}
//Položky objednávky
public ArrayList OrderItems
{
get
{
return m_orderItems;
}
}
}
public class OrderItem
{
private Order m_order;
private int m_orderItemsCount;
private decimal m_orderItemsPrice;
public OrderItem(Order parent)
{
if (parent == null)
throw new ArgumentNullException();
m_order = parent;
m_orderItemsCount = 0;
m_orderItemsPrice = 0;
}
public Order Parent
{
get
{
return m_order;
}
set
{
m_order = value;
}
}
//Počet kusů zboží v objednávce
public virtual int OrderItemsCount
{
get
{
return m_orderItemsCount;
}
set
{
m_orderItemsCount = value;;
}
}
//Celková cena všech kusů zboží v položce objednávce
public virtual decimal OrderItemsPrice
{
get
{
return m_orderItemsPrice;
}
set
{
m_orderItemsPrice = value;
}
}
public virtual void LoadOrSave(bool save)
{
//implementace perzistence
}
}
}
Thursday, October 07, 2004 8:31:00 PM (Central Europe Standard Time, UTC+01:00)
Programátorské hádanky

Thursday, September 23, 2004
Druhá malá programátorská hádanka na tento týden
Dokážete (bez spuštění programu) poznat, v čem bude provádění tohoto kódu z hlediska "selského programátorského rozumu" podivné a proč?
using
System;
namespace
ConsoleApplication24{
public
class
Class1
{
public
static
void
Calculate(
int
number)
{
}
}
public
class
Class2: Class1
{
public
static
void
Calculate(
long
number)
{
}
}
class
Test
{
[STAThread]
static
void
Main(
string
[]args)
{
Class2.Calculate(
int
.MinValue);}
}
}
Thursday, September 23, 2004 3:30:00 PM (Central Europe Standard Time, UTC+01:00)
Programátorské hádanky

Tuesday, September 21, 2004
Malá programátorská hádanka
Máte následující kód:
class
Test : BaseTest
{
private
string
m_rene;
public
Test() :
base
()
{
m_rene = "Rene";
}
public
override
void
WriteName()
{
Console.WriteLine(m_rene);
Console.Read();
}
}
Metoda WriteName vypíše za určitých podmínek jen prázdný řetězec - víte kdy? ;)
Update: A víte, jak se bude chovat stejný kód po přepsání do C++?
Tuesday, September 21, 2004 3:32:00 PM (Central Europe Standard Time, UTC+01:00)
Programátorské hádanky