Telepítés Google Cloudba Docker konténerből

Mostanában sokat kell a címben említett felhőben hegesztenem. Pár hete épp egy (sok) App Engine-en futó szervert kellett megreszelnem (oké, most már kezdenek furák lenni ezek az igék), és ennek kapcsán felmerült, hogy oké, tudom tudok telepíteni a gépemről, de hogyan mondom meg a CI/CD rendszernek, hogy tolja fel az appot a felhőbe?

Itt egy megoldás!

“Telepítés Google Cloudba Docker konténerből” olvasásának folytatása

Reklámok

Mit hozott a Build első keynote-ja?

Huh… Amúgy sem gyenge 3 órát végigülni, hát még ha ilyen sebességgel dobálják az ember arcába az agyzsibbasztó újdonságokat. Szerencsére a jó társaság javított a helyzeten. 🙂 Az alábbiakban megpróbálom összefoglalni, hogy mik voltak a Build 2014 első keynote-jának az újdonságai, és miért is ütnek akkorát. Figyelem, wall-of-text is coming!

“Mit hozott a Build első keynote-ja?” olvasásának folytatása

SQL Server Compact Edition felügyelete

Ritkán kell SQL Server Compact Editionnel dolgoznom, de akkor nagyon. 🙂 A minap is szembejött egy ilyen projekt, és most kerültem szembe azzal a problémával, hogy a Microsoft legújabb eszközei (gondolok itt a Visual Studio 2012-re, illetve az SQL Server Management Studio Express legutóbbi verziójára) már nem hajlandók összebarátkozni egy SQL CE adatbázissal. A régebbieket meg mostanában szedtem le. Mit lehet tenni?

“SQL Server Compact Edition felügyelete” olvasásának folytatása

Nyelvi aszinkronitás Windows Phone-on

Ne blogolj éjjel! Rögtön miután közzétettem a tegnapi bejegyzést, leesett, hogy eredetileg nem csak a Taskokig akartam bemutatni a UI tehermentesítését, hanem továbbmenni egy lépéssel, és megmutatni, hogy hogyan lehet WP7 alatt a C# 5.0-ban megjelent nyelvi aszinkronitást felhasználni.

“Nyelvi aszinkronitás Windows Phone-on” olvasásának folytatása

Task-alapú párhuzamosítás Windows Phone 7 alatt

A minap arról kérték a véleményemet, hogy hogyan érdemes WP7 alatt kódot a UI-száltól függetlenül futtatni, merthogy a Threadek (szálak) használata körülményessé tud válni, az APM pedig… APM. Nem kell magyarázni. 🙂 A válasz természetesen az, hogy Taskokkal érdemes. Erre persze az volt a válasz, hogy dehát Taskok nincsenek WP7 alatt…

“Task-alapú párhuzamosítás Windows Phone 7 alatt” olvasásának folytatása

Magyar nyelvű Windows Azure-könyv + interjú

Egy héten belül megjelenik itthon az első magyar nyelvű Azure könyv, a Windows Azure lépésről lépésre. A kiadó honlapján már elérhető a tartalomjegyzék, meg a szokásos áttekintés, borítóterv stb.

A megjelenés kapcsán a Microsoft szóra bírja a könyv egyes fejezeteinek szerzőit egy-egy rövid interjú erejéig. Ma (illetve már tegnap) szerénytelen személyem idézték meg egy ilyen lakonikus viviszekcióra. (Mea culpa, hosszú napom volt… 🙂 ) Ha már tényleg nincs jobb dolgod, átolvastad a 9gaget, 4chant, tumblr-t, végignézted az összes macskás videót a neten, és még mindig nem vagy álmos, akkor akár el is olvashatod az interjút itt.

Információ a hívó kódról C# 5-ben

A bejegyzés címe akár az is lehetett volna, hogy “a másik C# 5.0-újdonság”. Az alábbiakban tehát azt mutatom be, hogyan készíthetünk olyan metódusokat C#-ban, melyek információval rendelkeznek az őket meghívó kódról.

“Információ a hívó kódról C# 5-ben” olvasásának folytatása

Generikus metódus hívása futásidejű típusparaméterrel

//NOTE: a devportal OneTime bindinggal húzza be a postokat. 🙂 Mivel elég gyakori, hogy a publikálás után veszem észre, hogy összekevertem a télapó és a gestapo szavakat, hiába javítom, a devportalon nem változik. Javaslom, hogy aki neadjbéla arra vetemedik, hogy szerény kis agymenéseimmel múlatja az időt, kattanjon a postok alján lévő wordpress linkre, ott lesz a friss változat. Danke sün!

A generikus metódusokat/típusokat szeretjük, mert nagy flexibilitást, jobb teljesítményt és nagyobb típusbiztonságot adnak. Azonban semmi sincs ingyen – van, ahol nagyon meg tudja keseríteni az életünket az átállás generikus metódusokra. Vegyük a következő példát…

Jussunk el a problémáig!

Adott egy Arena nevű osztály, mely rendelkezik egy Harc nevű metódussal, amely két típusparaméterrel rendelkezik, továbbá megköti, hogy ezen T1 és T2 típusoknak kell, hogy legyen paramétermentes konstruktoruk, és meg kell valósítaniuk az IHarcképes interfészt. C#-ul mondva:

class Arena
{
    public string Harc<T1, T2>()
        where T1 : IHarcképes, new()
        where T2 : IHarcképes, new()
    {
        T1 t1 = new T1();
        T2 t2 = new T2();

        int delta = t1.GetHarcérték() - t2.GetHarcérték();
        if (delta > 0) return typeof(T1).Name + " az erősebb.";
        if (delta < 0) return typeof(T2).Name + " az erősebb.";
        return "Döntetlen.";
    }
}

interface IHarcképes
{
    int GetHarcérték();
}

Ahogy látható, a metódus létrehoz két objektumot, és az interfészmetódus segítségével megvizsgálja, melyik nyerne egy harcban. Tegyük fel, hogy sok osztályunk van, amelyeknek harcolniuk kell majd. Emellett szeretnénk ezeket párokba rendezni, mégpedig olyan módon, hogy a párokba rendezés dinamikusan történhessen, tehát ne legyen előre kőbe vésve. Néhány osztály, amivel el tudunk indulni:

class Katona : IHarcképes
{
    public int GetHarcérték() { return 1; }
}

class Ellenség : IHarcképes
{
    public int GetHarcérték() { return 2; }
}

class Lábas : IHarcképes
{
    public int GetHarcérték() { return 1; }
}

class Ellenlábas : IHarcképes
{
    public int GetHarcérték() { return 2; }
}

Érezhető, hogy a katona ellensége az ellenség lesz, illetve beigazolódik az is, hogy a konyhában minden lábasnak van egy ellenlábasa. (Maksa ftw!) Normál esetben a harcértéket valamiből kiszámolnánk; ehelyett itt sony-típusú randomszámokat adunk vissza. A párokba rendezést bízzuk egy osztályra:

class HarcpárTároló
{
    Dictionary<Type, Type> pairs = new Dictionary<Type, Type>();

    public HarcpárTároló()
    {
        pairs.Add(typeof(Katona), typeof(Ellenség));
        pairs.Add(typeof(Lábas), typeof(Ellenlábas));
    }

    public Type GetPairTypeFromType(Type t)
    {
        return pairs[t];
    }
}

Ebből gyárthatunk több leszármazottat is, és mindegyik a saját kis logikája alapján pároztathatja párosíthatja a típusokat. Eddig szép és jó. De hogyan hívjuk meg a Harc metódust? Próbáljuk meg valahogy…

Arena arena = new Arena();
HarcpárTároló hpt = new HarcpárTároló();

object egyik = new Lábas();
Type masik = hpt.GetPairTypeFromType(egyik.GetType());

arena.Harc<egyik.GetType(), masik>();  //compile-time error

Ez ugye fájdalmasan csúnya. Olyannyira, hogy le se fordul. (Sőt, ha valaki megpróbálta begépelni, érezhette, hogy az IntelliSense mindent megtesz, hogy akadályozza.) A probléma ugyebár az, hogy a generikus metódus meghívásához fordítási időben rendelkezésre kellene állnia a típusparamétereknek. Mit lehet tenni?

Tükrözés!

Talán ismerős lehet, hogy ismeretlen típusoknál a reflection segítségével elérhetünk ismeretlen metódusokat. De természetesen arra is képes a rendszer, hogy ismert típusok ismert metódusait adja vissza. 🙂

A metódus kiválasztása után csak plusz egy lépést kell elvégezni ahhoz, hogy működjön a dolog. Mivel itt generikus metódusról van szó, a metódus kiválasztása csupán a “nyílt” metódust adja vissza. Ez a generikus sablon, amit tulajdonképpen megírtunk C#-ban. Ahhoz, hogy ezt két konkrét típussal használhassuk, rá kell venni a fordítót, hogy készítse el a metódus nem-generikus változatát. (Ha a nyílt metódust hívnánk, egy InvalidOperationExceptiont kapnánk, ami arról tájékoztatna, hogy ez egy nyílt generikus metódust, és mint ilyen, meghívhatatlan. :)) Végül pedig ugyanúgy hívhatjuk a metódust, mintha bármilyen nem-generikus metódust hívnánk reflectionön keresztül: a zárt metódus már nem generikus.

MethodInfo openMeth = arena.GetType().GetMethod("Harc");
MethodInfo closedMeth = openMeth.MakeGenericMethod(
    new[] { egyik.GetType(), masik });
closedMeth.Invoke(arena, null);

Nem olyan szép, mintha meglennének előre a típusok, de ez így képes feldolgozni, ha csak futásidőben kapjuk meg őket. Készen vagyunk.

Lehetne ezt máshogy?

Természetesen: senki nem kötelez minket arra, hogy generikus metódust használjunk ott, ahol valami miatt kényelmetlen. A Harc metódust megírhatjuk típusmentesre is. Picit bonyolultabb lesz.

AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
public string HarcNonGeneric(Type t_t1, Type t_t2)
{
    if (!t_t1.GetInterfaces().Contains(typeof(IHarcképes)) ||
        !t_t2.GetInterfaces().Contains(typeof(IHarcképes)))
    {
        throw new InvalidOperationException(
            "Mindkét paramétertípus meg kell valósítsa az IHarcképes interfészt.");
    }

    IHarcképes t1 = (IHarcképes)Activator.CreateInstance(t_t1);
    IHarcképes t2 = (IHarcképes)Activator.CreateInstance(t_t2);

    int delta = t1.GetHarcérték() - t2.GetHarcérték();
    if (delta > 0) return t_t1.Name + " az erősebb.";
    if (delta < 0) return t_t2.Name + " az erősebb.";
    return "Döntetlen.";
}

Jobb ez a metódus? Röviden: nem, a generikus mindig szebb. 🙂 De ha objektívebben nézzük: le kell mérni, melyik mit tud.

AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English

Egymillió hívásnál…

Lefuttattam a generikus és a nemgenerikus változat meghívását 1 milliószor, és a kiváncsiság kedvéért a nemgenerikusat reflectionön keresztül is. Ha csak a metódushívásokat nézzük, előre látható, hogy a generikus változat szanaszét veri a másik kettőt. (ms, az alacsonyabb érték a jobb.)

Generic, reflection: 12091
NonGeneric, reflection: 20399
NonGeneric, nonreflection: 16904

Ha mindig, vagy legalábbis sokszor kell ugyanazokkal a típusokkal dolgozunk, ugyanarra a típusra lefuttatnunk a metódust, akkor tehát megéri generikusan implementálni. A metódus elkészítésének overheadje csak egy egyszeri overhead. (A teljesség kedvéért megjegyzem, hogy a gép egyéb dolgaitól függően volt egy 1-3 mp-es kilengés a futtatások között, de az arányok mindig így alakultak.)

Mi van azonban, ha egy típusra (típuspárra) csak egyszer futtatjuk le, és megyünk is tovább a következő típusra/típuspárra?

Generic, reflection: 25157
NonGeneric, reflection: 22699
NonGeneric, nonreflection: 16916

Mivel minden egyes metódushívás előtt le kell kérni a metódust, és legyártatni a zárt változatát, megfordult a dolog: a nem-generikus metódus itt minden hátránya ellenére is sokkal gyorsabb, mint a generikus. Tehát ilyen esetekre jobban járunk, ha nem generikusat készítünk, hanem maradunk a “jól bevált” C# 1.0-s módszernél. Persze most Activatorral dolgoztunk – ha ennek a tudása nem elég. és ConstructorInfokon keresztül kell dolgozni, az okozhat némi lassulást a nemgenerikus változatban.

Mára ennyi, most pedig vissza kódolni.

AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English