Soci (Soczó Zsolt) szakmai blogja

2017.08.18.

Protobuf.net

Filed under: .NET,Szakmai élet — Soczó Zsolt @ 13:24

Eszement gyorsan serializál!
https://code.google.com/archive/p/protobuf-net/wikis/GettingStarted.wiki

2015.12.22.

Egy példa mitől fordul le állandóan egy .NET project

Filed under: .NET,Szakmai élet — Soczó Zsolt @ 19:02

Bosszantó, amikor semmit nem változtatsz, mégis újrafordul pár project egy nagyobb solutionben. Ha bekapcsolod a diagnostic build loglevelt, akkor egyből kiderül az ok. Pl. most nálam:

Project ‘Basics’ is not up to date. Project item ‘C:\ATS\Basics\x64\lz4X64.dll’ has ‘Copy to Output Directory’ attribute set to ‘Copy always’.

Update: egyéb okok: felesleges referenciák illetve Resource-ként megjelölt file, ami nem is resource, csak sima xml, ki kell másolni a kimenetbe.

.NET fejtörő

Filed under: .NET,Szakmai élet — Soczó Zsolt @ 15:29

Élő kódból. Az első megoldás jól működik, a második nem, mi lehet az oka? A hibajelenség, hogy az első beállítja a TickerId-t az objektumon belül, a második nem.

Parallel.For(0, tickOhlcs.Count, i => tickOhlcs[i].SetTickerId(key.TickerId));

Parallel.ForEach(tickOhlcs, tickOhlc => tickOhlc.SetTickerId(key.TickerId));

2015.11.16.

TDD következő alkalom early bird

Filed under: .NET,Felhívás,Szakmai élet,Test Driven Development,Testing — Soczó Zsolt @ 23:19

Jövő januárban újra lesz TDD tanfolyam, most ősszel már nem volt időm betervezni egyet.

Aki december 1-ig jelentkezik, azt most 150e-ért csatlakozhat.

2015.05.08.

Task.Run Etiquette Examples: Don’t Use Task.Run in the Implementation

Filed under: .NET,.NET 4,.NET 4.5,ASP.NET,Szakmai élet — Soczó Zsolt @ 11:34

Az async – await dolgokkal fel lehet szabadítani pl. as ASP.NET által is használt ThreadPool szálakat, hogy míg egy hosszú ideig tartó nem CPU hanem IO intenzív folyamat fut, addig legyen szabad szál kiszolgálni a rendes, kicsi, gyors kéréseket.

De ha úgy aszinkronítunk egy blokkoló, IO intenzív kérést, hogy becsomagoljuk Task.Run-ba, akkor adtunk a sznak egy pofont, mert pont ugyanabból a ThreadPoolból vettünk el szálat, mint amit az ASP.NET is használ (feltételezve az alap TaskSchedulert használjuk). Ráadásul még context switch is lesz a szálak között, stb.

Az igazi aszinkron cuccosok (pl. .NET szerviz hívó osztályok és adatbázis kezelő osztályok) IO completion portot használnak, amivel sok blokkoló folyamatot tudnak monitorozni kevés szálon, nem minden egyes folyamathoz egy szálat használva, mint a Task.Run-os megoldás.

Bővebben a témáról itt.

2015.05.06.

Visual Studio 2015 debugger

Filed under: .NET,Szakmai élet,Visual Studio,Visual Studio 2015 — Soczó Zsolt @ 14:31

Amellett, hogy nagyon frankón néz ki a kis chartokkal a tetején, amit kiemelnék, alul a watch ablak. Működnek a lambdák a watchban, lehet debug time linqzgatni! :)

VS2015Debugger

2015.04.16.

Mire használja az MVC a machinekeyt?

Filed under: .NET,ASP.NET,mvc,Szakmai élet — Soczó Zsolt @ 22:51

A source alapján nekem úgy tűnik csak az AntiForgeryTokenhez. Van még szerintetek valami más szerepe is (nem webformsról beszélünk).

Tovább nézve látom az ASP.NET Identity is használja, a Tokeneket védeni.

2015.03.18.

EF őrület

Filed under: .NET,Adatbázisok,ADO.NET,Entity Framework,NHibernate,Szakmai élet — Soczó Zsolt @ 20:23

Ha az NHibernate tudja, hogy identity id generálási stratégia mellett, ha egy ojjektumnak nem 0 az idja, akkor az perzisztens, így nem kell újra beszúrni, az miért nem megy az EF-nek?

Próbálom használni az EF-et anélkül, hogy lemappelném az FK-kat property-ként, de látom széllel szemben megyek. Nincs cascade szabályozás sem, így ez úton nem mondhatom neki, hogy csak a gyereket szúrd be, a szülőt ne, mert az már perzisztens. Ah. Értem én, hogy nem ebbe az irányba kell haladnom, mert szembe fúj a szél, de nem szeretem azokat a modelleket, ahol az fk le van mappelve. Leaky abstraction. Az EF inkontinens, ez kell neki, a fene a hugyos józsiját.

Védje meg valaki, vagy mindjárt visszatérek NHibre, és kivágom a projektből az EF-et.

EF gyerek kollekció rendezés

Filed under: .NET,Adatbázisok,C#,Entity Framework,SQL Server,Szakmai élet — Soczó Zsolt @ 18:03

Néha szeretnénk nem csak egy entitás listát, hanem annak gyerekeit is rendeztetni, azaz az egy szülő alá tartozó gyerekeket order by-olni.

Egy lehetséges megoldás:

using (var c = new EdbContext())
{
    var jobs = c.LoaderJobs
        .Include("LoaderJobSteps")
        .Include("LoaderJobSteps.ExtractPathLocation")
        .Include("LoaderJobSteps.FormatFilePathLocation")
        .OrderBy(j => j.ExecutionOrder).ToList();

    //A bit complicated to be able to order LoaderJobSteps properly
    var x = jobs.Select(job => new { J = job, JS = job.LoaderJobSteps.OrderBy(js => js.ExecutionOrder).ToList() });

    return x.Select(f => f.J).ToList();
}

Szándékaim szerint a gyerekkollekciók order by-át is az adatbázissal végeztettem volna, de jól látható a kódból, hogy itt .netből történik a gyerekek (LoaderJobSteps) rendezése.
Ha kiveszem az első ToList()-et, akkor az EF helyesen áttolja a 2. order by-t is az SQL Serverre, de akkor meg nem tölti be az unokákat (LoaderJobSteps.ExtractPathLocation).
Ebben a példában nincs jelentősége hol rendezek, de ha valaki tudja, mitől nem megy ilyenkor az Include, érdekelne a megoldás.

Ha benn van az első ToList(), akkor az SQL ok, benne van minden eagerly loaded entitás, de nincs benne order by a gyerekekre, az a LINQ2Objects fogja végrehajtani. (Extent2-re nincs order by).

SELECT 
    [Project1].[Id] AS [Id], 
    [Project1].[Description] AS [Description], 
    [Project1].[ExecutionOrder] AS [ExecutionOrder], 
    [Project1].[C1] AS [C1], 
    [Project1].[Id1] AS [Id1], 
    [Project1].[StepName] AS [StepName], 
    [Project1].[ExecutionOrder1] AS [ExecutionOrder1], 
    [Project1].[ProcedureNamePrepare] AS [ProcedureNamePrepare], 
    [Project1].[ProcedureNameImport] AS [ProcedureNameImport], 
    [Project1].[ProcedureNameLoad] AS [ProcedureNameLoad], 
    [Project1].[ExtractFileName] AS [ExtractFileName], 
    [Project1].[FailOnMissingFile] AS [FailOnMissingFile], 
    [Project1].[FormatFileName] AS [FormatFileName], 
    [Project1].[Id2] AS [Id2], 
    [Project1].[FolderPath] AS [FolderPath], 
    [Project1].[Id3] AS [Id3], 
    [Project1].[FolderPath1] AS [FolderPath1], 
    [Project1].[LoaderJobId] AS [LoaderJobId]
    FROM ( SELECT 
        [Extent1].[Id] AS [Id], 
        [Extent1].[Description] AS [Description], 
        [Extent1].[ExecutionOrder] AS [ExecutionOrder], 
        [Join2].[Id1] AS [Id1], 
        [Join2].[StepName] AS [StepName], 
        [Join2].[ExecutionOrder] AS [ExecutionOrder1], 
        [Join2].[ProcedureNamePrepare] AS [ProcedureNamePrepare], 
        [Join2].[ProcedureNameImport] AS [ProcedureNameImport], 
        [Join2].[ProcedureNameLoad] AS [ProcedureNameLoad], 
        [Join2].[ExtractFileName] AS [ExtractFileName], 
        [Join2].[FailOnMissingFile] AS [FailOnMissingFile], 
        [Join2].[FormatFileName] AS [FormatFileName], 
        [Join2].[LoaderJobId] AS [LoaderJobId], 
        [Join2].[Id2] AS [Id2], 
        [Join2].[FolderPath1] AS [FolderPath], 
        [Join2].[Id3] AS [Id3], 
        [Join2].[FolderPath2] AS [FolderPath1], 
        CASE WHEN ([Join2].[Id1] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
        FROM  [dbo].[LoaderJob] AS [Extent1]
        LEFT OUTER JOIN  (SELECT [Extent2].[Id] AS [Id1], [Extent2].[StepName] AS [StepName], [Extent2].[ExecutionOrder] AS [ExecutionOrder], [Extent2].[ProcedureNamePrepare] AS [ProcedureNamePrepare], [Extent2].[ProcedureNameImport] AS [ProcedureNameImport], [Extent2].[ProcedureNameLoad] AS [ProcedureNameLoad], [Extent2].[ExtractFileName] AS [ExtractFileName], [Extent2].[FailOnMissingFile] AS [FailOnMissingFile], [Extent2].[FormatFileName] AS [FormatFileName], [Extent2].[LoaderJobId] AS [LoaderJobId], [Extent3].[Id] AS [Id2], [Extent3].[FolderPath] AS [FolderPath1], [Extent4].[Id] AS [Id3], [Extent4].[FolderPath] AS [FolderPath2]
            FROM   [dbo].[LoaderJobStep] AS [Extent2]
            LEFT OUTER JOIN [dbo].[PathLocation] AS [Extent3] ON [Extent2].[ExtractPathLocationId] = [Extent3].[Id]
            LEFT OUTER JOIN [dbo].[PathLocation] AS [Extent4] ON [Extent2].[FormatFilePathLocationId] = [Extent4].[Id] ) AS [Join2] ON [Extent1].[Id] = [Join2].[LoaderJobId]
    )  AS [Project1]
    ORDER BY [Project1].[ExecutionOrder] ASC, [Project1].[Id] ASC, [Project1].[C1] ASC

Az első ToList() nélkül:

SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Description] AS [Description], 
    [Extent1].[ExecutionOrder] AS [ExecutionOrder]
    FROM [dbo].[LoaderJob] AS [Extent1]
    ORDER BY [Extent1].[ExecutionOrder] ASC

Hm. Tippek?

Közben rájöttem, megválaszolom magamnak a kérdést. :) A végére kell rakni az include-okat:

using (var c = new EdbContext())
{
var jobs = c.LoaderJobs
.OrderBy(j => j.ExecutionOrder);

//A bit complicated to be able to order LoaderJobSteps properly
var x = jobs.Select(job => new { J = job, JS = job.LoaderJobSteps.OrderBy(js => js.ExecutionOrder) });

return x.Select(f => f.J).Include(“LoaderJobSteps”)
.Include(“LoaderJobSteps.ExtractPathLocation”)
.Include(“LoaderJobSteps.FormatFilePathLocation”).ToList();
}
[/source]

SELECT 
    [Project1].[Id] AS [Id], 
    [Project1].[Description] AS [Description], 
    [Project1].[ExecutionOrder] AS [ExecutionOrder], 
    [Project1].[C1] AS [C1], 
    [Project1].[Id1] AS [Id1], 
    [Project1].[StepName] AS [StepName], 
    [Project1].[ExecutionOrder1] AS [ExecutionOrder1], 
    [Project1].[ProcedureNamePrepare] AS [ProcedureNamePrepare], 
    [Project1].[ProcedureNameImport] AS [ProcedureNameImport], 
    [Project1].[ProcedureNameLoad] AS [ProcedureNameLoad], 
    [Project1].[ExtractFileName] AS [ExtractFileName], 
    [Project1].[FailOnMissingFile] AS [FailOnMissingFile], 
    [Project1].[FormatFileName] AS [FormatFileName], 
    [Project1].[Id2] AS [Id2], 
    [Project1].[FolderPath] AS [FolderPath], 
    [Project1].[Id3] AS [Id3], 
    [Project1].[FolderPath1] AS [FolderPath1], 
    [Project1].[LoaderJobId] AS [LoaderJobId]
    FROM ( SELECT 
        [Extent1].[Id] AS [Id], 
        [Extent1].[Description] AS [Description], 
        [Extent1].[ExecutionOrder] AS [ExecutionOrder], 
        [Join2].[Id1] AS [Id1], 
        [Join2].[StepName] AS [StepName], 
        [Join2].[ExecutionOrder] AS [ExecutionOrder1], 
        [Join2].[ProcedureNamePrepare] AS [ProcedureNamePrepare], 
        [Join2].[ProcedureNameImport] AS [ProcedureNameImport], 
        [Join2].[ProcedureNameLoad] AS [ProcedureNameLoad], 
        [Join2].[ExtractFileName] AS [ExtractFileName], 
        [Join2].[FailOnMissingFile] AS [FailOnMissingFile], 
        [Join2].[FormatFileName] AS [FormatFileName], 
        [Join2].[LoaderJobId] AS [LoaderJobId], 
        [Join2].[Id2] AS [Id2], 
        [Join2].[FolderPath1] AS [FolderPath], 
        [Join2].[Id3] AS [Id3], 
        [Join2].[FolderPath2] AS [FolderPath1], 
        CASE WHEN ([Join2].[Id1] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
        FROM  [dbo].[LoaderJob] AS [Extent1]
        LEFT OUTER JOIN  (SELECT [Extent2].[Id] AS [Id1], [Extent2].[StepName] AS [StepName], [Extent2].[ExecutionOrder] AS [ExecutionOrder], [Extent2].[ProcedureNamePrepare] AS [ProcedureNamePrepare], [Extent2].[ProcedureNameImport] AS [ProcedureNameImport], [Extent2].[ProcedureNameLoad] AS [ProcedureNameLoad], [Extent2].[ExtractFileName] AS [ExtractFileName], [Extent2].[FailOnMissingFile] AS [FailOnMissingFile], [Extent2].[FormatFileName] AS [FormatFileName], [Extent2].[LoaderJobId] AS [LoaderJobId], [Extent3].[Id] AS [Id2], [Extent3].[FolderPath] AS [FolderPath1], [Extent4].[Id] AS [Id3], [Extent4].[FolderPath] AS [FolderPath2]
            FROM   [dbo].[LoaderJobStep] AS [Extent2]
            LEFT OUTER JOIN [dbo].[PathLocation] AS [Extent3] ON [Extent2].[ExtractPathLocationId] = [Extent3].[Id]
            LEFT OUTER JOIN [dbo].[PathLocation] AS [Extent4] ON [Extent2].[FormatFilePathLocationId] = [Extent4].[Id] ) AS [Join2] ON [Extent1].[Id] = [Join2].[LoaderJobId]
    )  AS [Project1]
    ORDER BY [Project1].[ExecutionOrder] ASC, [Project1].[Id] ASC, [Project1].[C1] ASC

Hm, mégse jó, nincs benne az sql-ben a 2. order by. Szóval a kérdés nyitott, át lehet tolni adatbázis oldalra a child kollekció order by-t?

2015.03.06.

Entity Framework bulk műveletek

Filed under: .NET,Adatbázisok,ADO.NET,Entity Framework,NHibernate,Szakmai élet — Soczó Zsolt @ 11:56

Amint ezt beépítik az EF-be, attól a pillanattól kezdve az EF végre rendes versenytársa lesz az NHibernate-nek.

Ráadásul, a doski azt sejteti, hogy menni fog identity oszlopokra is, az nem megy nhibbel.

Izgalmas fejlemények, meg kéne venni az egész motyót az msnek, de gyorsan.

2015.02.27.

.NET fejtörő 6. – megoldás

Filed under: .NET,Security,Szakmai élet,Teaser — Soczó Zsolt @ 13:36

Feladat.

Nincs mit írnom a megoldásról, Varga Tamás kolléga (ezek köszönet érte) annyira részletesen, alaposan kielemezte a témát a kommentek között, hogy ennél én csak kevesebbet tudnék írni, övé a szó, olvassátok.

TDD akció újra

Filed under: .NET,Felhívás,Szakmai élet,Test Driven Development,Unit Test — Soczó Zsolt @ 13:30

Tavaly már volt egy ilyen akcióm, az megtöltötte a termet (150k < 200k). Gyere, ne maradj le róla.

2015.02.22.

.NET fejtörő 5. – megoldás

Filed under: .NET,C#,Szakmai élet,Teaser — Soczó Zsolt @ 18:18

A fejtörő.

Molnár Csaba olyan teljesen megválaszolta a kérdést (köszönet érte), hogy a kommentjét egy az egyben bepasztázom:

C#-ban az idexer egy indexelt property, aminek alapértelmezetten Item a neve. Ezért fordítási hibát kapunk ennél a kódnál, hogy már van definíció az Item-re.
Ezt kétféle módon tudjuk elkerülni:
1. Az Item property-t átnevezzük valami másra.
2. Használjuk az indexeren az IndexerNameAttribute-ot, amivel megadhatjuk, hogy milyen néven jöjjön létre az indexer (ne Item néven).

Én személy szerint nem erőltetném a névütközést, inkább választanék más nevet.

Ami pluszként érdekes a példában (nekem nem volt magától értetődő), hogy lehet használni a params módosítót indexer esetén is.

2015.02.14.

.NET fejtörő 4. – megoldás

Filed under: .NET,IIS7,Security,Szakmai élet,Teaser — Soczó Zsolt @ 16:23

Kérdés: miért nem jó, ha az ASP.NET Machine Key-emet Random.NextBytes()-szal generálom?

A Machine Key-t alapban viewstate validálásra használja az ASP.NET. HMAC algoritmussal csinál egy hasht, amihez a Machine Key-t mint kulcsot is felhasználja. Ez a kevésbé problémás dolog. Ami sokkal veszettebb, hogy amikor beléptetünk valakit az ASP.NET forms security-vel, akkor a beléptetett felhasználót azonosító adatot ezzel a Machine Key-jel titkosítják. Ha valaki megismeri ezt a kulcsot, akkor tud generálni kamu kukit, amibe azt a user id-t ír be, amit csak akar. Azaz meg tud személyesíteni másokat. Ebből aztán lesz spoofing, vagy akár elevation of privilege. Magyarul senki nem szeretné, ha bárki más beléphetne a nevében egy védett website-on. Például az internetes bankjába.

Szóval, talán most már érthető, a Machine Key-t nem szeretnénk, ha bárki megszerezné vagy kitalálná. Megszerezni csak a site feltörésével lehet, és admin jogokkal, tegyük fel ez nem történt meg. Ha azonban a véletlen sorozat generátorunk kiszámítható, akkor más is ugyanazzal az algoritmussal tud generálni egy olyan kulcsot, amit én is generáltam. És már jönnek is be más nevében.

A .NET Random pszeudo-random generátor, azonos seed-del mindig ugyanaz a sorozat jön ki belőle. Azt mondjátok de én ravasz vagyok, és beadom a DateTime.Now.Ticket neki inputként, az úgysem tudja a támadó. Nem tudja, de pörgetni ő is tudja ezt a számot addig, amíg ki nem találja a megfelelő seedet.

Mi a megoldás? Olyan random generátor kell, ami teljesen kiszámíthatatlan. Pl. a termikus zaj digitalizálva tökéletesen jó erre a célra. Ha ilyen modul nincs a gépben, akkor a Windows megpróbál valami nagyon randommal kijönni, például összerakva olyan vad perf counter értékeket, mint a proci ventilátor sebessége és egyebek.

A lényeg, hogy ha cripto szinten random érték kell, akkor az RNGCryptoServiceProvider típust kell használni erre a célra.

Egyébként meg IIS 7.5-től machine key-t tud generálni az IIS Manager GUI is. :)

2015.02.10.

.NET fejtörő 3. – megoldás

Filed under: .NET,Szakmai élet,Teaser — Soczó Zsolt @ 17:45

Íme a kiírás.

Álljon itt újra a kód is:

struct Counter
{
    int counter;
    public override string ToString()
    {
        return counter++.ToString(CultureInfo.InvariantCulture);
    }
}

[TestMethod]
public void Teaser3()
{
    var sb = new StringBuilder();
            
    var sz = new Counter();
            
    sb.Append(sz);
    Object p = sz;
    Object o = p;
    sb.Append(sz);
    sb.Append(o);
    sb.Append(p);
    sb.Append(o);

    Assert.AreEqual("01234", sb.ToString());
}

Először lemaradt a feladatból a Counter struktúra, anélkül nem volt sok értelme a feladatnak, ezért az első pár választ nyilván félre mehetett.
A feladatban az a trükk, hogy nem class, hanem struktúra a Counter típus. A StringBuilderben a végén 00012 lesz. Miért?

Az sz egy a veremben tárolt struktúra. Az sb.Append() (ebben az esetben) objektumot vár paraméterül (ami reference type), amin meghívja a ToString() metódust, és ennek kimenetét rakja bele az építendő stringbe. Azonban az sz egy struktúra, value type, így azt a CLR-nek fel kell másolnia a heapre. Ezt hívják boxingnak. Ezen pont után a ToString() már a másolaton hívódik meg, az eredeti sz counter mezeje érintetlen marad.
Mivel postfix ++ operátort használunk, a kifejezés kimenete a növelés előtti érték lesz, azaz 0. Ez az első számunk.
Az Object p = sz explicit felboxolja sz-t a heapre. Az Object o = p pusztán egy másik referencia lesz ugyanerre az értékre.
Ezek után sb.Append(sz) újra boxol és kiírja a 0-t, mint a korábbi esetben. Ez a 2. számunk. Sokan szerintem itt már 1-et vártak, ami így is lenne, ha a Counter classként lenne definiálva.
Az sb.Append(o) az eddig még érintetlen felboxolt példányon hívódik meg. Mivel megint csak postfix ++ van, ez is 0 lesz. Ez a 3. 0.
Az sb.Append(p) ugyanezen példányra mutat, így végre ő már megnövelheti a számlálót 2-re, és visszaadhatja az 1-et. Ez a 4. számunk, ami végre 1.
Az sb.Append(o) pedig újra végigjátssza a növelést a más ismerős példánnyal, így jön ki belőle 2.

Ha a típusunk class lett volna, akkor jött volna ki belőle 01234.

A példának látszólag nincs jelentősége, a generikus típusok óta valóban kevesebb baj van a struktúrákkal. De még .NET 1.0-ban láttam olyat, amikor HashTable[“valami”]++ után a x = HashTable[“valami”] változatlan értéket adott vissza, meglepve a kollégákat. Most már talán érthető, miért.

2015.02.06.

.NET fejtörő 3. hiánypótlás

Filed under: .NET,Szakmai élet,Teaser — Soczó Zsolt @ 12:38

Elnézést azoktól, akik filóztak a 3. .NET feladaton, elfelejtettem belerakni a Counter típust, anélkül semmi értelme a feladatnak. Így már érthető, miért nem jött rá megoldás. :)

Most akkor neki lehet esni még egyszer.

2015.02.05.

.NET fejtörő 4.

Filed under: .NET,Szakmai élet,Teaser — Soczó Zsolt @ 21:54

Ez most egy elméleti kérdés lesz. Van egy web farmom. Az ASP.NET Machine Key-emet legeneráltam a Random.NextBytes() segítségével, és beraktam minden gép machine.configjába. Mi a probléma a megoldásommal?

.NET fejtörő 3 – nincs megoldás?

Filed under: .NET,Szakmai élet,Teaser — Soczó Zsolt @ 21:48

Itt volt ez a fejtörő, de nem jött rá megoldás. Ennyire nem nehéz. Valaki?

.NET fejtörő 2. megoldás

Filed under: .NET,Szakmai élet — Soczó Zsolt @ 21:44

Feladat itt.

Emlékeztetőűl a feladat:

var sb = new StringBuilder();

for (int i = 0; i < 10; i++)
{
    sb.Append(i + ' ');
}

A művelet kimenete:
32333435363738394041

Miért?

i integer, ‘ ‘ char. A char nem más, mint egy 16-bites numeric (ordinal) érték, mi implicit konvertálható más, nagyobb vagy azonos méretű egészekké.
Azaz a ‘ ‘ szóköz karakter 32-es kódját kell hozzáadni a ciklusváltozóhoz, ezért jön ki egy számsorozat végeredményként.

2015.01.22.

.NET fejtörő 3.

Filed under: .NET,Szakmai élet,Teaser — Soczó Zsolt @ 08:00

Update: bocs, a Counter osztály lemaradt, így nem volt értelme a feladatnak.

Piros vagy zöld lesz a teszt kimenete? Válaszokat indoklással kommentben várom. A hozzászólások moderálva vannak, hogy 2 napot tudjam késleltetni a válaszokat, így mindenkinek lesz ideje gondolkodni. Jó filózást!


struct Counter
{
    int counter;
    public override string ToString()
    {
        return counter++.ToString(CultureInfo.InvariantCulture);
    }
}

[TestMethod]
public void Teaser3()
{
    var sb = new StringBuilder();
            
    var sz = new Counter();
            
    sb.Append(sz);
    Object p = sz;
    Object o = p;
    sb.Append(sz);
    sb.Append(o);
    sb.Append(p);
    sb.Append(o);

    Assert.AreEqual("01234", sb.ToString());
}

A Test Driven Development tanfolyam következő felvonása 2015. február kilencedikén lesz, szeretettel várlak.

Newer Posts »

Powered by WordPress