\


 Wednesday, 06 August 2008
Recenze: Effective C++ 55 Specific Ways to Improve Your Programs

Effective C  Při nákupu na Amazonu jsem neodolal a do košíku jsem vložil už třetí edici netradičně psané knihy  Effective C++ od Scotta Meyerse. Konvenčnímu stylu průměrných odborných knížek se Effective C++ se vymyká už jen tím, že nejde o další popularizující a tisíckrát opakovanou snůšku jednoduchých rad a receptů psanou za účelem "za 21 dní či hodin uděláme z naprostého technického idiota sebevědomého technického idiota, jehož mozek dokáže na pohovoru nějakému jinému (bez) mozku z personální agentury úspěšně předstírat znalost nějaké technologie". Scott Meyers se nesnaží ani předstírat, že se z jeho knihy naučíte základy C++, ale předpokládá, že jste schopni v C++ programovat a že jste si již stačili uvědomit  temná zákoutí  jazyka C++, nebo jste v nich v horším případě na některém projektu začali i bloudit. Kniha Effective C++ je pobídkou, abyste si osvojili 55 postupů z různých výrazových prostředků jazyka C++, které vám umožní temná zákoutí jazyka C++ obcházet. Pro vývojáře, jejichž "mateřským" jazykem je C# nebo JAVA, může být zajímavé, že ve třetí edici Scott asi na základě svých špatných zkušeností na vícero místech v knize opakuje: "Takto je to možná v Javě, možná vám to nevadí ani v C#, ale zapamatujte si, že C++ není JAVA ani C#." Pořád lepší být mentorován a poučován od člověka, který svoje varování vyřkne proto, že se pravděpodobně při svých konzultacích setkal s odstrašujícími ukázkami kódu, který byl zcela bezmyšlenkovitě převeden ze C# do C++, než být vlečen projektovým osudem vtěleným do Ganttových diagramů , který umí být mnohem nemilosrdnější než běžný lidský osud a donutí ve svých dosavadních garbage collectorem stvrzených jistotách spokojeně si hovící vývojáře zabývat se C++ bez možnosti utéct zpět do závětří "managed" kódu. :-)

V úvodu Scott popíše, jaké termíny a pojmy by měl každý vývojář v C++ znát a hned v prvním článku popíše své vidění jazyka C++. Jazyk C++ je pro něj spíše federaci poměrně samostatných jazyků, než jedním klasicky strukturovaným programovacím jaykem. C++ vám dovoluje psát programy v klasickém "C" stylu, můžete pracovat s třídami, dědičností a virtuálními metodami stejně jako v každém jiném jazyce podporujícím OOP. Také ale se můžete nechat zlákat šablonami a metaprogramováním a využít toho, že na první pohled ničím nevynikající a dříve některými jen za chytřejší preprocesor  považované šablony jsou "turingovsky" úplným jazykem. V knize je za autonomní jazyk považována i knihovna STL, i když autor vysvětluje, že za dalšího člena C++ federace ji považuje hlavně proto, že přináší další programové konvence a idiomy (funktory, "chytré" pointery", iterátory, ...), které musíte bezpodminečně ovládat , chcete-li použivat další knihovny třetích stran, jež jsou na těchto standardních technikách a postupech často založeny.

V dalších článcích se Scott zabývá nutností inicializovat všechny proměnné. Při zdůrazňování důležitosti konstantních členů třídy pookřejete, že konečně nějaký autor pořádně vysvětlil, jak správně použít klíčové slova mutable, ale možná nebudete spokojeni s motivací pro dvojí přetypovávání (const_cast) u konstatních metod třídy (například indexer - operator[]), které se odkazují na své nekonstantní protějšky, protože v nich nechcete duplikovat kód.

Dalším velkým tématem jsou konstruktory, destruktory a operátory přiřazení. V článcích se dozvíte, jak neopakovat typické chyby při psaní kopírovacích konstruktorů nebo operátorů přiřazení, jak zajistit, že při vytváření hluboké kopie objektu inicializujete i zděděné členy, nebo proč je pro vaši aplikaci smrtící, když z destruktoru objektu necháte vybublat výjimku. I u těchto nepříliš zajímavých témat oceníte Scottův živý a vášní pro své téma prodchnutý jazyk. Když upozorňuje na to, v jakých případech vývojáře kompilátor nebude nijak varovat, že kopírovací konstruktory a operátory přiřazení nefungují správně, sarkasticky k tomu dodá, že jde pravděpodobně o odplatu za to, že už nenecháte kompilátor, aby si sám vyhrál s deklarací kopírovacích konstruktorů a operátorů a přiřazení. Když popisuje, jak sdílet kód mezi vícero konstruktory, místo zabíhání do nesmyslných podrobností debatu rázně utne tvrzením, že se sice můžete zkusit odkázat z jednoho konstruktoru na jiný konstruktor a že na první pohled mohou vaše konstrukce vypadat pěkně, ale že stejně jde o nesmysl a jazyk C++ nic takového nedovoluje. Chcete-li sdílet kód v konstruktorech, dostanete praktickou radu, ke které byste asi sami stejně dospěli, abyste společný kód vyčlenili do samostatné privátní "init" metody. 

V dalších částech se Scott zabývá chytrými pointery. Celá kapitola 4 s články 18 až 25 je vyhrazena návrhu správného rozhraní třídy. Principy jako "navrhujte rozhraní tak, aby jej bylo jednoduché použít, ale velmi komplikované zneužít" asi v nikom nevyvolají nevoli nebo chuť polemizovat. S článkem preferujte nečlenské a non-přátelské (non-friend) funkce nad členskými už asi ale každý nebude souhlasit, i když Scottovy argumenty nejsou špatné. Mně je ale bližší C# a další jazyky, které vás nutí umístit každou funkci do těla třídy. V C++  uplatňuji pouze příslovečnou výjimku z pravidla u operátorů a funkcí, u nichž vyžaduji, aby k implicitní konverzi argumentů mohlo dojit u všech argumentů, což je téma, které i Scott pěkně popisuje v článku 25 nazvaném "Declare non member functions when type conversions should apply to all parameters".

Slyšeli-li jste někdy letmo o PIMPL idiomu a divili jste se, k čemu by vůbec byl dobrý, nebo vám vadila u projektu dlouhotrvající a nutná rekompilace po změně jednoho hlavičkového souboru z nějaké knihovny? V knize se dozvíte, jak "kompilační" závislosti omezit právě s využitím do všech podrobností dokonale vysvětleného PIMPL postupu. Kdo je stále zajatcem bludu, že dědičnost a virtuální metody jsou jediným všemocným kladivem na všechny problémy, měl by si pořádně pročíst kapitolu zabývající se dědičností, ve které Scott zmiňuje, jak poznat a implementovat vztah "je podtypem" (veřejná dědičnost"), nebo "využiji nějaké služby jiné třídy" (kompozice, privátní dědičnost). Také fandové vícenásobné dědičnosti by si měli podrobně přečíst, proč Scott její použití nijak nezakazuje, ale jemně v názvu článku 40 varuje, že by měli být soudní. Protože jinak při šíleném křížení tříd můžete velmi rychle  o rozum a logický úsudek přijít, dodal bych já. A možná rádi, abyste nemohli už dnes přesně usuzovat, kolik ještě stačíte na dohodnuté podpoře aplikace za několik let prodělat. :)

Šablony jsou tématem kapitoly 7, ale výklad není veden příliš do hloubky. Scott se spíše soustřeďuje na řešení klasických "špeků", jimž se při použití šablon nevyhnul asi nikdo. Podědili jste z šablonové třídy, voláte metodu z bázové třídy a kompilátor protestuje, Scott ukazuje, jak "chybu" odstranit - ať už použitím klíčového slova this (this->MetodaZBazoveTridy();), instruováním překladače o existenci metody v bázové třídě za pomoci klíčového slova using (using BazovaTrida<Typ>::MojeMetoda;) nebo uvedením jména bázové třídy před jménem metody při volání (BazovaTrida<Typ>::MojeMetoda();). Sympatické je, že nezůstane u prostého výčtu možných řešení problému, ale Scott upozorní, v čem tkví nedostatky jednotlivých řešení, takže u poslední varianty se vám ihned dostane varování, že jde o nejméně vhodné řešení, protože bude-li metoda MojeMetoda virtuální, tak jste se explicitním odkazem na implementaci metody v bázové třídě o virtuální chování mnohdy nechtěně a navíc hloupě připravili. Pěkný je i článek 45, který dostačujícím a přehledným způsobem popíše význam šablonových funkcí (nejen) na příkladu užitečného zobecněného kopírovacího konstruktoru se šablonou a nechybí  v něm ani vysvětlení, proč v C++ zobecněný a na šablonách založený konstruktor nikdy nenahradí běžný nešablonový konstruktor.  Důležitá je i kapitola, která shrnuje, proč byste měli nečlenské funkce definovat přímo v šablonové třídě, jestliže požadujete, aby všechny argumenty metody podporovaly automatické konverze. Opomenut není ani význam rysů (traits) u šablonového programování.

V další kapitole Scott zmíní, kdy je vhodné nahradit standardní operátory new a delete a také, jak nejlépe vyhovět všem konvencím při nahrazování operátorů new a delete. (článek 52 pojednává o nutnosti poskytnout "placement" operator delete, jestliže jsme se rozhodli používat vlastní placement "new" operator)

V poslední kapitole s radami, které se nevešly jinam, kniha dává na pranýř ty programátory, kteří si myslí, že varování kompilátoru nejsou přece žádnou chybou a že tedy na ně nemusejí brát ohledy, protože by jim zkazila nadšení, že tu svou nádhernou sbírku chybových bajtů zkompilovali, nebo protože si už vypěstovali vůči varovným hláškám selektivní slepotu. Poslední dva články vyzývají vývojáře, aby si osvojili algoritmy, kontejnery, iterátory a postupy využité v STL a v studnici nápadů zvané BOOST.

Líbí  se mi, že na konci každého článku je rychlé shrnutí, co byste si měli určitě zapamatovat.

Ani kniha Effective C++ není dokonalá a najdeme v ní mnoho kapitol, u nichž si zkušenější vývojář řekne, že existují i pokročilejší postupy. Například v článcích o objektech a šablonách by se slušelo zmínit, jak pomocí částečné specializace můžeme odstraňovat/přidávat modifikátory const.

template<class T>struct ConstHelper

typedef const T Add;

typedef T Remove;  

typedef const T Invert;  

 

 

};

template<class T>struct ConstHelper<const T>

{  

typedef const T Add;

typedef T Remove;  

typedef T Invert;  

 

};

 

typedef typename ConstObject<T>::Add const_parameter;

 

Šablony a jejich využití při metaprogramování je vměstnáno do jednoho přehledového článku ("článek 48 - Be Aware of template metaprogramming). Výjimky jsou zmíněny jen okrajově. Tyto výtky ale platí jen zčásti, protože Scott napsal druhý díl nazvaný More Effective C++ a dluh vůči knihovně STL splatil v další knize Effective STL.

Scottovi se podařilo napsat čtivou a přitom po odborné stránce nijak neošizenou knihu, jejíž brilantní formulace i postřehy jsou projevem zajímavé osobnosti, která netrpí tou příšernou a nudnou falešnou skromností, která alespoň mě vadí u jiných autorů, okázale zdůrazňujících ve svém díle  všechny spolupracovníky, známé, přicmrdávače i vtěrky, aby za každou cenu dali najevo, jak oceňují práci druhých a jak jsou jen malým mravenečkem při stavbě velkého díla, jímž je jejich kniha. Tento druh povinné a společensky přívětivě přijímané falešné skromnosti mi totiž přijde jen nepříliš rafinovanou zástěrkou pro skutečnou a nelichotivou skromnost duševní (snad jen té :-) ) potence a navýsost egoistickou snahou možný publikační neúspěch (pod) průměrného, frázovitého, a dokonce mnohdy i po té, tolikrát zdůrazňované jako jediné významné či rozhodující, odborné stránce nepřesného díla omluvit a zdůvodnit slovy: "Podívejte se, že za ten paskvil opravdu nemohu sám". Bohužel ani kvantitativně početné stádo nevyvolených duševně chudých nemůže supeřit s jedním Scottem Meyersem. Scott si nebere žádné servítky a jak se dá z jeho knihy vytušit, nečiní mu žádný problém v jím (spolu)pořádaných anketách nominovat a jistě po těžké úvaze :-) i zvolit na čelní místa (a já dodávám zcela oprávněně) sebe a své knihy. A svým kritikům, kteří na něho vytahují, že není žádný programátor s rozsáhlou praxí, s klidem výstižně odpovídá, že on strávil mnoho času studiem jazyka a všech jeho rysů včetně slepých uliček právě proto, aby ostatním pomohl v jejich praktickém programování.  Teoretický i praktický rozum se doplňují a nekonkurují si. Je tristní pohled na vývojáře, který si osvojil 10% syntaktických i sémantických konstrukcí a knihoven z  nepřeberného bohatství každého programovacího jazyka a pak své praktické "informační systémy" plácá s pomocí jedné bábovičky. Osobně tomu říkám syndrom "všechno vyřeší volání grid.DataBind()", což ale je srozumitelné asi jen ASP.NET vývojářům, ale podobné typy vývojářů(?) se najdou všude.

Motem knihy je citát z Petroniova Satyriconu: "Wisdom and Beauty form a very rare combination".  Této knize se to podařilo.



Wednesday, 06 August 2008 18:29:08 (Central Europe Standard Time, UTC+01:00)       
Comments [2]  Ostatní


 Wednesday, 30 July 2008
GSM Net Monitor verze 0.7.0. Alfa

Homepage aplikace.

Instalační cab.

Návod na rozchození lokalizace pozice pomocí BTS

Změny ve verzi  0.0.7.

  1. Odstraněna chyba, která se mohla vyskytnout při odesílání požadavku na server => Net Monitor vypisoval chybu 2 (špatné formátování).

 

Důležité:

Před instalací nové verze vypněte v aplikaci sledování sítě.

Protože se jedná o AlFA preview, doporučuji před instalaci Net Monitoru mít v zařízení např. SPB Pocket Plus a v něm aktivovaný safe boot - jestliže by vám "vytuhlo" zařízení, nebudete muset dělat HR (Hard Reset), protože můžete při startu zařízení dočasně deaktivovat Today pluginy.

Po upgradu budete muset pravděpodobně znovu zadat svůj registrovaný email a přístupový kód. Pokud jste jej zapomněli, jděte na stránku http://gsmadmin.renestein.net a zadejte znovu svůj email. Aplikace vám nabídne opětovné zaslání emailu.



Wednesday, 30 July 2008 16:06:40 (Central Europe Standard Time, UTC+01:00)       
Comments [4]  Mobilitky | Nativní kód | Net Monitor


 Monday, 28 July 2008
Technologie použité při vývoji Net Monitoru

V mailu jsem dostal dotaz, v "čem je napsán" GSM Net Monitor. Možná to bude zajímat i někoho dalšího, protože v Net Monitoru se potkává paleolit s postmodernim věkem . :) Při vývoji aplikace si uvědomíte nejen, kde vám .Net Framework šetří práci, ale  i to, kde by jeho režie byla spíš na obtíž, a v čem exceluje C++.  Soukromý povzdech: C# generika je skvělá, ale C++ šablony u mě kralují...

Serverová část - databáze MSSQL 2005, ASP.NET 3.5, Windows Communication Foundation 3.5 s podporou toho, čemu se podivně říká REST, LINQ s vlastními "extenzními" metodami, jazyk C#.

Klientská část na PDA  - pouze Windows API  - protože jsem chtěl, aby aplikace neměla přehnané paměťové nároky, nepoužil jsem ani COM XML parser od Microsoftu a jen doufám, že Windows CE team portuje desktopovou knihovnu XmlLite. Jazyk C++.



Monday, 28 July 2008 10:11:54 (Central Europe Standard Time, UTC+01:00)       
Comments [0]  Mobilitky | Nativní kód | Net Monitor


 Friday, 25 July 2008
GSM Net Monitor verze 0.6.0. Alfa Preview - !podpora lokalizace polohy bez GPS na vámi zvolených mapách! Místo Google Maps Mobile třeba Seznam...

 

Homepage aplikace.

Hlavní změny:

  1. Lokalizace polohy dle BTS, ke které jste přihlášeni. Přesný návod, jak zprovoznit tuto funkci, naleznete níže.
  2. Aplikace je určena pouze pro zařízení Windows Mobile 5 Professional (zařízení s dotykovou obrazovkou) a vyšší.
  3. Odstraněna spodní lišta  ("telefon - indikátor zapnuté/vypnuté rádiové části") , která dle uživatelských ohlasů zbytečně zabírala místo. Lišta se vrátí v některé další verzi po přidání dalších indikátorů, kdy už bude mít větší smysl. V nastavení si budete vždy moci vybrat, zda má být lišta viditelná.
  4. V nastavení si můžete zvolit preferovanou výšku pluginu na Today obrazovce.
  5. Vylepšen instalační cab, který automaticky deaktivuje stávájící verzi GSM .Net Monitor na Today obrazovce a zapne po instalaci jeho novou verzi. Přesto ihned po instalaci doporučuji soft reset zařízení.
  6. Zobrazení mapy s lokalizovanou pozicí pod/nad Today pluginem nebo přes celou obrazovku. Pro lepší představu se podívejte na snímky obrazovek v tomto spotu.
  7. Zcela přepracován způsob práce s RIL vrstvou.
  8. Odstraněny chyby (a zcela jistě zaneseny nové) :).
  9. Změna grafiky.

 

Instalace

Protože se jedná o AlFA preview, doporučuji před instalaci Net Monitoru mít v zařízení např. SPB Pocket Plus a v něm aktivovaný safe boot - jestliže by vám "vytuhlo" zařízení, nebudete muset dělat HR (Hard Reset), protože můžete při startu zařízení dočasně deaktivovat Today pluginy.

Důležité: Pokud používáte předchozí verzi .Net Monitoru, pro jistotu ji sami deaktivujte na Today obrazovce a poté odinstalujte.

  1. Z adresy http://blog.renestein.net/__DOWNLOAD/NetMonitorTodayInstall.CAB si stáhněte instalační CAB.
  2. CAB spusťte a potvrďte případně hlásky zabezpečení.
  3. Resetujte (Soft reset) zařízení.

Návod na zprovoznění lokalizace polohy:

  1. Nainstalujte aplikaci GSM .Net Monitor.
  2. Na adrese http://gsmadmin.renestein.net/ si musíte vygenerovat unikátní přístupový kód. Stačí zadat platný email, opsat "captcha" kód a kliknout na tlačítko 'Vygenerovat přístupový kód". Pozor si dejte na to, že některé (zvláště  freemailové ) schránky mohou email umístit do složky se spamem, nebo rovnou smazat.

    Pristupovy_Kod_Net_Monitor

     

  3. Z adresy gsmservicenoreply@renestein.net vám přijde email s přístupovým kódem, který musíte aktivovat kliknutím na odkaz v emailu. Pokud se aktivace podaří, zobrazí se vám následující informace.

    Aktivovan_Ucet

  4. Přístupový kód a registrovaný email je nutné zadat v nastavení v GSM Net  Monitoru. Z kontextového menu vyberete položku Nastavení a poté přejdete na záložku BT GPS souřadnice, kde vyplníte pole Email a Klíč (přístupový kód).  Dbejte na to, abyste správně opsali i velikost písmen v přístupovém kódu. Potvrďte nové nastavení kliknutím na tlačítko OK.

    BTGPS

  5. V nastavení, na záložce Základní nastavení, můžete změnit časový interval, v jakém jsou zjišťovány informace o GSM síti. Výchozí hodnota je 60 sekun, můžete nastavit např. 5 sekund.
  6. Jestliže jste vše zadali správně, spusťte sledování BTS v GSM Net Monitoru vybráním položky 'Sledovat informace o GSM síti' (to můžete udělat také kliknutím na zelené tlačítko v levém horním rohu aplikace). Poté vyberte z kontextového menu položku Zobrazovat mapu.
    Důležité podrobnosti: Jestliže chcete mapu zobrazovat kdykoli po spuštění pluginu, můžete v nastavení (opět záložka BT GPS souřadnice - viz obrázek u bodu 4) zaškrtnout položku 'Zobrazovat mapu po spuštění'´. Samozřejmě při nedostupnosti WiFi Net Monitor používá placené GPRS/EDGE připojení. Mapa je viditelná po přepnutí na záložku GPS data v pluginu. Mapa je viditelná pouze, když jsou k dispozici platné GPS souřadnice. Jestliže jste na místě, kde GPS souřadnice BTS nejsou známy nebo jste bez GSM signálu, aplikace mapu skryje. Mapa NENÍ skryta, jestliže je zobrazena přes celou obrazovku (full screen).

    ZobrazeniMapy

  7. Na celou obrazovku mapu přepnete zobrazením kontextového menu na mapě a vybráním jediné položky ´Celá obrazovka´.  Zobrazování mapy na celé obrazovce zrušíte opětovným zobrazením kontextového menu na mapě a vybráním (nyní zaškrtnuté) položky ´Celá obrazovka´.

    PrechodCelaObrazovka   CelaObrazovkaVypnout

     

Poznámky:

  • Po instalaci je v aplikaci přednastaveno zobrazování pozice na wap verzi map Seznamu. Můžete ale použít jakoukoli další mapu, které stačí předat GPS souřadnice.

http://wap.mapy.cz/search?from=&query=LOC:{LAT} {LON}&mapType=base&zoom=14

V URL map stačí zadat, kam má aplikace doplnit GPS souřadnice  - řetězec {LAT}  bude nahrazen zeměpisnou šířkou a řetězec  {LON} zeměpisnou délkou.

 

  • Aplikace zjišťuje souřadnice na adrese http://gsm.renestein.net/NetMonitorService.Svc/GSMTEST/GsmQuery(...) . Toto URL je zadáno v textovém poli Služba na záložce GPS souřadnice a neměli byste ho měnit.
  • Záložka Podrobnosti pracuje stejně jako v předchozích verzích jen s lokálními csv seznamy BTS ze serveru GSMWeb.

 

Komerční využití GSM Net Monitoru i přidružených služeb je striktně zakázáno. Pokud máte zájem o komerční služby, kontaktujte mě prosím.

!Za žádné přímé, nepřímé, reálné či domnělé škody způsobené aplikací nenesu žádnou odpovědnost!

Užijte si to. :-)

Různé obrazovky:

Aktualizace 31.7.:

Ještě pro informaci:
Aplikace se snaží vypisovat chyby.
Pokud je chyba se znaménkem - (např. -1001), je chyba pravděpodobně na klientovi (není dostupné internetové připojení apod.).
Pokud je chyba bez znaménka -, požadavek odmítl můj server (např. chyba 1 znamená, že jste nebyli úspěšně ověřeni - nemáte platné uživatelské jméno, opsali jste špatně přístupový kód atd.).
Pokud budete mít nějaký problém, opiště mi hlavně prosím číslo chyby.
Pokud BTS není v databázi - aplikace vypisuje chyba na serveru 1000. Nic se neděje, pouze pro tuto BTS nemám ještě GPS souřadnice.

BTGPS CelaObrazovkaVypnout PrechodCelaObrazovka  ZadaniKlice ZobrazeniMapy NM1 NMPodrobnosti Nastaveni OAplikaci DatabazeBTS



Friday, 25 July 2008 12:18:26 (Central Europe Standard Time, UTC+01:00)       
Comments [2]  .NET Framework | Mobilitky | Net Monitor


 Monday, 07 July 2008
Víte, u kolika českých BTS už zná Google jejich přibližnou polohu? Aneb Google Maps Mobile

Google má ve svém program Google Maps Mobile užitečnou funkci pro přibližné určení polohy bez použití GPS. Volba "Moje Poloha" se pokusí o lokalizaci na základě pozice GSM buňky (buněk), ke které je momentálně přihlášen váš mobilní telefon. Od počátku bylo zřejmé, že Google musí sbírat informace o pozici GSM buněk "za pochodu", protože žádné oficiální, a navíc celosvětové, databáze BTS neexistují. Google tedy pravděpodobně na své servery anonymně odesílá informace o aktuální GSM buňce společně s GPS souřadnicemi vždy, když v GM Mobile zapnete GPS. Viz také diskuze pod článkem na Navigovat.cz, který upozorňoval na novou verzi GM Mobile. Dohady potvrdil i můj pokus, kdy jsem několikrát na místech, kde aplikace GM Mobile nejprve sveřepě odmítala zobrazit pozici na základě buňky, pustil GPS, a za několik hodin/dní jsem již byl lokalizován jen přes funkci "Moje poloha".

A jak je na tom Google dnes (7. 7. 2008) s "pokrytím" v ČR? Do statistiky jsou zahrnuty jen buňky v GSM síti (ne UMTS) společností T-Mobile, O2 a Vodafone, jejichž (neoficiální) seznamy naleznete na gsmweb.cz.  Celkový počet GSM buněk, u nichž jsem zjištoval "pokrytí" Googlem, je tedy dán součtem evidovaných GSM buněk v odpovídajících seznamech na gsmweb.cz.

Celkem sledováno GSM buněk: 34 773

Z toho buněk s GPS souřadnicemi: 19 435 

T-Mobile celkem buněk / z toho s GPS souřadnicemi:  11 060 / 6 379

O2 celkem buněk/z toho s GPS souřadnicemi: 11588 / 6 838

Vodafone celkem buněk/z toho s GPS souřadnicemi:  12125 / 6218

 

Prosím, neptejte se, jak jsem se k těmto údajům dostal, stejně vám to neřeknu ani nenapíšu. :)  A do Googlu asi také nemá cenu psát. :)

 



Monday, 07 July 2008 18:50:45 (Central Europe Standard Time, UTC+01:00)       
Comments [6]  Mobilitky | Nativní kód


 Thursday, 05 June 2008
Windows Mobile - skrytí kontaktů na SIM kartě

Dnes mi jeden email připomněl, že jsem svůj jednoduchý prográmek na skrytí kontaktů na SIM kartě dal k dispozici jen na některých fórech o Windows Mobile, kde prý už nebyl k nalezení.

Program využije každý, kdo není spokojen s tím, že po restartu MDA (soft reset) se vždy v seznamu kontaktů mísí kontakty v paměti MDA s kontakty na SIM kartě. Skrytí kontaktů pomocí hacku v registrech je pouze dočasné. Můj program zajistí, že po restartu jsou kontakty na SIM kartě vždy skryty.

Následující cab stačí zkopírovat do MDA a spustit.

Stáhnout RStein.HideSimInstall.cab



Thursday, 05 June 2008 19:27:53 (Central Europe Standard Time, UTC+01:00)       
Comments [0]  Mobilitky


 Wednesday, 28 May 2008
Prezentace z přednášky Slasti, strasti a propasti vývoje pro Windows Mobile

Slidy z přednášky Slasti, Pasti, strasti a propasti nativního/řízeného (managed) vývoje pro zařízení s operačním systémem Windows Mobile si můžete nyní stáhnout.

Slasti_Strasti_Propasti_WindowsMobile

 

 

 



Wednesday, 28 May 2008 22:47:45 (Central Europe Standard Time, UTC+01:00)       
Comments [0]  Compact .Net Framework | Mobilitky | Nativní kód | Net Monitor | Wifi Profiles Windows Mobile


 Sunday, 18 May 2008
Pozvánka na říjnový termín kurzu Objektovými principy a návrhovými vzory řízený design a vývoj kvalitních aplikací

Dovolte mi, abych Vás všechny pozval na podzimní termín kurzu Objektovými principy a návrhovými vzory řízený design a vývoj kvalitních aplikací.  Po vyhodnocení některých připomínek jsme se rozhodli změnit místo, kde se školení uskuteční.

Hotel VILLA Praha
Okrajní 1
100 00 Praha 10

Změna místa přinese účastníkům hlavně možnost zaparkovat auto přímo u hotelu a také to, že oběd (v ceně školení) dostaneme přímo v hotelu (oběd může prý obsluha donést až do učebny) a nebudeme tak nuceni trávit dlouhý čas čekáním na nějakého unuděného a pomalého pingla v poloprázdné pizzerii nebo podobném podniku s mizernou kuchyní.

Termín:

20. 10. - 22. 10. 2008

Organizační informace ke kurzu

Program kurzu

Zaregistrované ohlasy na školení :

http://blog.renestein.net/ct.ashx?id=10d7acf8-1026-43fe-b1f1-54fccb69105b&url=http%3a%2f%2fwww.jirifabian.net%2fwordpress%2f%3fp%3d157

http://blog.renestein.net/ct.ashx?id=10d7acf8-1026-43fe-b1f1-54fccb69105b&url=http%3a%2f%2fwww.rarous.net%2fclanek%2f143-skoleni-oop-uml-a-navrhovych-vzoru.aspx

 

Update: Nový ohlas

"Rene Stein pořádá opět svůj kurz o OOP - více na jeho blogu. Měl jsem možnost účastnit se školení od pana Kravala i školení pana Steina a doporučil bych spíše ten posledně jmenovaný. Je tak nějak více o praxi a z praxe. Oproti tomu kurz pana Kravala je spíše teoretický, Ale každému může vyhovovat něco jiného." Zdroj  - Martin's world



Sunday, 18 May 2008 12:11:09 (Central Europe Standard Time, UTC+01:00)       
Comments [0]  Analytické drobky | Kurzy UML a OOP | Návrhové vzory | UML


 Friday, 09 May 2008
LINQ II - přetypovávání i vnořených anonymních datových typů z jiné assembly

V předchozím spotu jsem byl schopen pracovat s anonymními datovými typy, i když byly dotazy a výsledné sady dat vytvořeny v jiné assembly. Odstranění vrozené xenofobie v praxi.:)

Náš kód ale vygeneruje výjimku, jestliže anonymní datový typ z jiné assembly obsahuje další vnořené anonymní datové typy jako v následujícím upraveném příkladu. Vlastnost InnerAT vrací další anonymní datový typ, který  pro zajímavost obsahuje odkaz ještě na další anonymní datový typ.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LINQTEST
{
    public class TestAT
    {
        public static object GetResult()
        {
            string[] rows = { "Toyota", "Lexus", "Audi" };

            var test = from row in rows
                       select new
                       {
                           FirstLetter = row[0],
                           Index = 110,
                           Original = row,
                           InnerAT = new { X = row[1], B = new {A=1}}
                       };
            
            return test;

        }
    }
}

Řešení spočívá v úpravě extenzí a to tak, že přidáme privátní metodu GetTypeInstance a přeneseme do ní většinu kódu z extenze ToAnonymousType. Metoda GetTypeInstance při neshodě datového typu očekávaného parametrem "našeho - v naší assembly dostupného" konstruktoru anonymního datového typu a datového typu vlastnosti anonymního datového typu z "cizí" assembly rekurzivně přenese data z "cizího" anonymního datového typu do "našeho".

 

using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Reflection;
using System.Collections;
using LINQTEST;

namespace LINQAnonymous
{
    /// <summary>
    /// Rozšíření pro LINQ
    /// </summary>
    static class RSLinqExtensions
    {

        /// <summary>
        /// Metoda přetypuje objekt na anonymní typ, jehož struktura byla předána v parametru <paramref name="prototype"/>
        /// </summary>
        /// <typeparam name="T">Kompilátorem odvozený anonymní typ</typeparam>
        /// <param name="prototype">Prototyp se strukturou anonymního typu</param>
        /// <returns>Instanci anonymního typu, nebo null, jestliže konverzi nelze provést</returns>
        /// <remarks>Metoda se pokusí převést data z různých assembly</remarks>
        public static T ToAnonymousType<T>(this object obj, T prototype)
                                        where T: class
        {
            
            
            T atiObj = obj as T;
            
            if (atiObj == null)
            {
                
                atiObj = GetTypeInstance(obj, prototype.GetType()) as T;
               
            }
                                                     
            return (atiObj);
        }
    

        private static object GetTypeInstance(object obj, Type expected)
        {
            object atiObj = null;

            ConstructorInfo constructorInfo = expected.GetConstructors()[0];
                
                if (constructorInfo == null)
                {
                    return null;
                }

                ParameterInfo[] paramInfos = constructorInfo.GetParameters();                
                PropertyInfo[] origProperties = obj.GetType().GetProperties();
                

                if (paramInfos.Count() != origProperties.Count())
                {
                    return null;
                }

                object[] paramArgs = new object[paramInfos.Count()];


                for (int i = 0; i < paramArgs.Length; i++)
                {
                    PropertyInfo origProperty = origProperties.Where(prop => prop.Name == paramInfos[i].Name).FirstOrDefault();

                    if (origProperty == null)
                    {
                        return null;
                    }

                    object val = origProperty.GetValue(obj, null);
                    if (origProperty.PropertyType != paramInfos[i].ParameterType)
                    {
                        val = GetTypeInstance(val, paramInfos[i].ParameterType);
                    }

                    paramArgs[i] = val;
                }

                atiObj = constructorInfo.Invoke(paramArgs);
                return atiObj;
        }
        /// <summary>
        /// Metoda vrátí
        /// </summary>
        /// <typeparam name="T">Kompilátorem odvozený anonymní typ</typeparam>
        /// <param name="prototype">Prototyp se strukturou anonymního typu</param>
        /// <returns>List instancí anonymního typu, nebo null, jestliže konverzi nelze provést</returns>
        /// <remarks>Metoda se pokusí převést data z různých assembly</remarks>
        public static List<T> CastToList<T>(this object obj, T prototype)
                                 where T : class
        {
            List<T> list = new List<T>();
            IEnumerable<T> enumerable = obj as IEnumerable<T>;

            if (enumerable != null)
            {
                list.AddRange(enumerable);
            }
            else
            {
                    IEnumerable enumObjects = obj as IEnumerable;
                    if (enumObjects == null)
                    {
                        return null;
                    }
                    
                foreach (object enumObject in enumObjects)
                    {
                        T currObject = ToAnonymousType(enumObject, prototype);
                        if (currObject == null)
                        {
                            //K čistění listu by neměl být důvod, ale garantujeme, že nevrátíme částečně naplněný list
                            list.Clear();
                            return list;
                        }

                        list.Add(currObject);
                    }
                
            }

            return list;
        }
    }
    

Při přetypovávání stačí stále jen zadat prototyp anonymního datové typu.

 

//Anonymní typ z jiné assembly!
            var result2 = TestAT.GetResult().CastToList(new {FirstLetter = default(char), 
                                                        Index =default(int),
                                                        Original = default(string),
                                                        InnerAT = new { X = default(char), B = new { A = default(int) } }
            })
                                                       ;
            foreach (var res in result2)
            {
                Console.WriteLine(res.FirstLetter);
                Console.WriteLine(res.Original);
            }


            Console.WriteLine(TestAT.
                                    GetResult().
                                    CastToList(new
                                    {
                                        FirstLetter = default(char),
                                        Index = default(int),
                                        Original = default(string),
                                        InnerAT = new { X = default(char), B = new { A =default(int)} }
                                    }
                                    ).
                                    Where(car => car.FirstLetter == 'T')
                                     .FirstOrDefault()
                                     .ToString());
            Console.ReadLine();


Friday, 09 May 2008 09:09:26 (Central Europe Standard Time, UTC+01:00)       
Comments [0]  .NET Framework | ASP.NET | Compact .Net Framework | LINQ | Windows Forms


 Thursday, 08 May 2008
LINQ - anonymní typ deklarovaný v jedné assembly dostupný v metodách další assembly?
.Net Framework

Anonymní datové typy v LINQu nelze použít jako návratový typ z metody a jediný způsob, jak anonymní typ z metody předat, je použít jako návratovou hodnotu typ object, protože v .Net Frameworku - jak je všeobecně známo - všechny třídy přímo či nepřímo dědí z třídy Object. Navíc platí, že anonymní typ je kompilátorem vždy deklarován jako internal a jeho použití je tak striktně omezeno na jednu assembly.

Jde o rozumné omezení a anonymní datové typy bychom neměli zneužívat k nesmyslům typu "hezká syntaxe pro generování objektů Dictionary", které si našly cestu i do připravovaného (a už dnes "přehypovaného") MVC frameworku pro ASP.NET.

V různých diskuzích se ale stále dokola objevuje dotaz, jak anonymní typ z metody vráti. A každé omezení se dá samozřejmě obejít - když nefunguje ani bodový systém na silnicích, proč nenajít hrubý trik ve stylu "osoby blízké" i pro erozi různých omezení u anonymního datového typu. :) Znovu alibisticky varuji všechny před zařazením následujících nehezkých triků do svého arzenálu běžných postupů při vývoji, protože všechny postupy spoléhají na chování kompilátoru C#, které není garantováno a které se může v další verzi nebo i jen při vydání service packu .Net Frameworku bez varování změnit.

Pro vrácení anonymního datového typu z metody použijeme hezký hack od Tomáše, který se ujal pod názvem "Cast By Example". Zjednodušeně řečeno - sice nemůžeme používat při přetypovávání názvy anonymních datových typů (tříd), protože anonymní datové typy jsou generovány až při kompilaci, ale můžeme kompilátoru dát při přetypování "vzor", jaký anonymní datový typ nám bude vyhovovat. Podrobnosti si můžete najít v odkazovaném článku Tomáše Petříčka  = zde jen připomenu, že technika využívá současného chování kompilátoru, který pro různé deklarace anonymních datových typů se stejnými vlastnostmi generuje v jedné assembly vždy právě jednu třídu.

Napsal jsem jednoduše použitelné extenze, které vám dovolí nejen přetypovat jednu instanci "object" na anonymní datový typ, ale můžete přetypovat množiny záznamů na (anonymně ;-)) typovou kolekci List<NějakýAnonymniTyp>, a dokonce je možné jednoduše použít anonymní datové typy z jiné assembly.

 

/// <summary>
    /// Rozšíření pro LINQ
    /// </summary>
    static class RSLinqExtensions
    {

        /// <summary>
        /// Metoda přetypuje objekt na anonymní typ, jehož struktura byla předána v parametru <paramref name="prototype"/>
        /// </summary>
        /// <typeparam name="T">Kompilátorem odvozený anonymní typ</typeparam>
        /// <param name="prototype">Prototyp se strukturou anonymního typu</param>
        /// <returns>Instanci anonymního typu, nebo null, jestliže konverzi nelze provést</returns>
        /// <remarks>Metoda se pokusí převést data z různých assembly</remarks>
        public static T ToAnonymousType<T>(this object obj, T prototype)
                                        where T: class
        {
            
            
            T atiObj = obj as T;
            
            if (atiObj == null)
            {

                ConstructorInfo constructorInfo = typeof(T).GetConstructors()[0];
                
                if (constructorInfo == null)
                {
                    return null;
                }

                ParameterInfo[] paramInfos = constructorInfo.GetParameters();                
                PropertyInfo[] origProperties = obj.GetType().GetProperties();
                

                if (paramInfos.Count() != origProperties.Count())
                {
                    return null;
                }

                object[] paramArgs = new object[paramInfos.Count()];


                for (int i = 0; i < paramArgs.Length; i++)
                {
                    PropertyInfo origProperty = origProperties.Where(prop => prop.Name == paramInfos[i].Name).FirstOrDefault();
                    
                    if (origProperty == null)
                    {
                        return null;
                    }
                                        
                    
                    paramArgs[i] = origProperty.GetValue(obj, null);                    
                }
                
                atiObj = constructorInfo.Invoke(paramArgs) as T;
            }
            
            return (atiObj);
        }
    
        /// <summary>
        /// Metoda vrátí
        /// </summary>
        /// <typeparam name="T">Kompilátorem odvozený anonymní typ</typeparam>
        /// <param name="prototype">Prototyp se strukturou anonymního typu</param>
        /// <returns>List instancí anonymního typu, nebo null, jestliže konverzi nelze provést</returns>
        /// <remarks>Metoda se pokusí převést data z různých assembly</remarks>
        public static List<T> CastToList<T>(this object obj, T prototype)
                                 where T : class
        {
            List<T> list = new List<T>();
            IEnumerable<T> enumerable = obj as IEnumerable<T>;

            if (enumerable != null)
            {
                list.AddRange(enumerable);
            }
            else
            {
                    IEnumerable enumObjects = obj as IEnumerable;
                    if (enumObjects == null)
                    {
                        return null;
                    }
                    
                foreach (object enumObject in enumObjects)
                    {
                        T currObject = ToAnonymousType(enumObject, prototype);
                        if (currObject == null)
                        {
                            //K čistění listu by neměl být důvod, ale garantujeme, že nevrátíme částečně naplněný list
                            list.Clear();
                            return list;
                        }

                        list.Add(currObject);
                    }
                
            }

            return list;
        }
    }

Komentáře u metod by měly dostatečně popisovat funkci extenzí. Metoda ToAnonymousType předpokládá, že chcete přetypovat na instanci anonymního typu (např. při použití metody Single v LINQu), metoda CastToList pracuje s množinou (IEnumerable<T>) instancí anonymního datového typu. Většina kódu v obou metodách ošetřuje situaci, kdy pracujete s anonymním datovým typem z jiné (referencované) assembly, jehož data je potřeba přenést do instance anonymního datového typu v aktuální assembly.

Použití extenzí - nejprve u anonymního datového typu deklarovaného v assembly, ve které je také náš LINQ dotaz.

using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Reflection;
using System.Collections;
using LINQTEST;

class Program
    {

        //Anonymní typ deklarovaný v této (exe) assembly
        private static object GetLetters()
        {
           string[] names = {"Rene", "Petra", "Kamilka"};

           var test = from name in names
                      select new {FirstLetter = name[0], Index=1};
           return test;
        }


        static void Main(string[] args)
        {
            var result = GetLetters().CastToList(new {FirstLetter = default(char),
                                                      Index =default(int)}
                                                 );
            foreach (var res in result)
            {
                Console.WriteLine(res.FirstLetter);
            }

}

Metodě CastToList jsme predali "vzor" anonymího datového typu (new {FirstLetter = default(char), Index =default(int)}) a hodnoty vlastností jsme u prototypu inicializovali s využitím klíčového slova default. V metodě Main v cyklu foreach je funkční intellisense a můžeme pracovat zcela typově s proměnnou res. Jenom zdůrazním, že nyní žádná reflexe nebyla použita! Metoda CastToList s využitím automatické typové inference kompilátoru pouze zkopírovala prvky v IEnumerable<T> do našeho typového generického Listu.

if (enumerable != null)
            {
                list.AddRange(enumerable);
            }

Reflexe je využita při konverzi anonymního typu deklarovaného v jiné assembly. Předpokládejme, že v jiné assembly nazvané např. LINQTest máme další metodu vracející množinu dat skrytou opět za obecným rozhraním "služebníka zcela neužitečného" neboli třídy object.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LINQTEST
{
    public class TestAT
    {
        public static object GetResult()
        {
            string[] rows = { "Toyota", "Lexus", "Audi" };

            var test = from row in rows
                       select new { FirstLetter = row[0],
                                    Index=110,
                                    Original = row
                                  };
            
            return test;

        }
    }
}

Zkompilovanou assembly LINQTest zareferencujeme v našem projektu. Kód pro práci s anonymní datovým typem v jiné assembly se z pohledu uživatele LINQ extenze nijak nezměnil od předchozího příkladu.

 

class Program
    {


        static void Main(string[] args)
        {
            //Anonymní typ z jiné assembly!
            var result2 = TestAT.GetResult().CastToList(new {FirstLetter =  default(char), 
                                                        Index =default(int),
                                                        Original = default(string)}
                                                       );
            foreach (var res in result2)
            {
                Console.WriteLine(res.FirstLetter);
                Console.WriteLine(res.Original);
            }


            Console.WriteLine(TestAT.
                                    GetResult().
                                    CastToList(new
                                    {
                                        FirstLetter = default(char),
                                        Index = default(int),
                                        Original = default(string)
                                    }).
                                    Where(car => car.FirstLetter == 'T')
                                     .FirstOrDefault()
                                     .ToString());
            Console.ReadLine();
        }
    }

Jak si můžete všimnout, po cyklu foreach si požádám o data z jiné assembly znovu a poté nad vrácenou typovou kolekci vytvořím další projekci. A ani mě nemusí zajímat, že se mi pod rukama zcela změnil typ používaných objektů. :-)

Docela zábavná záležitost ne? ;-)

LINQ II - přetypovávání i vnořených anonymních datových typů z jiné assembly



Thursday, 08 May 2008 15:00:43 (Central Europe Standard Time, UTC+01:00)       
Comments [0]  .NET Framework | ASP.NET | Compact .Net Framework | LINQ | Windows Forms