Archive for the ‘.NET’ Category

Alapban egy Dependency property nem kétirányú bindingos

Monday, June 20th, 2011

Meg kell adni a regisztrációjakor explicit, ha azt akarjuk, az legyen.


public static readonly DependencyProperty MyPropertyProperty =
    DependencyProperty.Register(
         "MyProperty",
         typeof(int),
         typeof(Window1),
         new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

1 órámat ismét elvittek. :)

Gondolatok a queue alapú kliens-szerviz kommunikációhoz

Thursday, June 16th, 2011

Az előző post kommentjei alapján (amit nagyon köszönök mindenkinek) nem kaptam sok bátorítást az aszinkron, queue alapú, kérés-választ különválasztó gazdag kliens - szerviz kommunikációhoz, úgy tűnik senki nem csinált ilyet, így nem akarok úttörő lenni a témában.
Ehhez még hozzájárul, hogy hétvégén méregettem az MSMQ teljesítményét. Azért ezt, mert a WCF is erre épít, és pl. az NServiceBus is.

A tesztkód 1.5kByteos üzeneteket rak át egyik sorból a másikba. Az ötlet innen jött, csak többszálasítottam.

A tesztkód:


using System;
using System.Diagnostics;
using System.Messaging;
using System.Threading;

namespace MsmqTran
{
    class Program
    {
        private const int NumberOfTests = 1000;
        private const int MaxDop = 10;
        private static readonly ManualResetEvent[] WaitForEmpty = new ManualResetEvent[MaxDop];

        static void Main()
        {
            var q1 = new MessageQueue(@".\private$\test_queue1");
            var q2 = new MessageQueue(@".\private$\test_queue2");

            Console.WriteLine("Filling source queue...");
            var b = new byte[1500];
            using (var msmqTx = new MessageQueueTransaction())
            {
                msmqTx.Begin();
                for (int i = 0; i < NumberOfTests; i++)
                {
                    q1.Send(b, msmqTx);
                }
                msmqTx.Commit();
            }

            q2.Purge();
            Console.WriteLine("Starting to move data from source queue to destination queue");

            var sp = Stopwatch.StartNew();

            for (int i = 0; i < MaxDop; i++)
            {
                WaitForEmpty[i] = new ManualResetEvent(false);
                ThreadPool.QueueUserWorkItem(o => ProcessMsg(q1, q2, (ManualResetEvent)o), WaitForEmpty[i]);
            }

            WaitHandle.WaitAll(WaitForEmpty);

            Console.WriteLine("Duration: {0}ms, throughput: {1:F0} messages/s", sp.ElapsedMilliseconds, 1000.0 * NumberOfTests / sp.ElapsedMilliseconds);
        }

        private static void ProcessMsg(MessageQueue q1, MessageQueue q2, ManualResetEvent w)
        {
            while (true)
            {
                using (var msmqTx = new MessageQueueTransaction())
                {
                    msmqTx.Begin();

                    Message message;
                    try
                    {
                        message = q1.Receive(TimeSpan.FromMilliseconds(0), msmqTx);
                    }
                    catch (MessageQueueException e)
                    {
                        Console.WriteLine(e);
                        w.Set();
                        break;
                    }

                    q2.Send(message, msmqTx);

                    msmqTx.Commit();
                }
            }
        }
    }
}

A gépemen 50 tran/sec-kel megy 1 szálon, és 200 fölé nem nagyon megy. Jó, ez laptop, de relációs adatbáziskezelővel (sql server és oracle is fut a gépen) több ezer tran/seccel mennek a dolgok. Szóval ez elég gázosan lassú. Emellett csúnya leállásokról is írnak a blogokban, amikor beáll az msmq.

Marad a aszinkronított WCF egyelőre, csak a szerverről visszafelé hívásokat tervezem queue alapon megcsinálni, WCF msmq bindinggal. Így tudom értesíteni az appokat polling nélkül. Erre 3 okom van most:
1. Az offline (disconnected) pessimistic lock feloldódott, lehet szerkeszteni valamit.
2. Frissíteni kell a kliens cache-ben valamit.
3. Email jellegű üzenetküldés az appok között.

Köszönöm még egyszer az építő javaslatokat.

Message alapú LOB app tervezés

Saturday, June 11th, 2011

Próbálom megtörni magamban a megszokott gondolkodási sémákat. Tervezek egy nagy, többrétegű LOB alkalmazást. A szervizrétegnek elsődlegesen a WPF rich klienst kell kiszolgálni, de jó lenne, ha mobil kliensek is tudnák ezt fogyasztani.
Ha a szerviz interfész finom felbontású, sok kicsi metódussal, akkor a kommunikáció sok időt rabol el, lassú lesz az app (chatty interfész).
Ha durva felbontású (chunky), akkor megvan a veszélye, hogy a fogyasztó WPF app formjaihoz lesz illesztve, célirányosan, így akkor meg mobil kliensek nem fogják tudni hatékonyan fogyasztani.
Egy érdekes alternatívát láttam a probléma feloldására itt és itt.
Ebben az összes kliens-szerviz kommunikáció message alapú, teljesen aszinkron. Egy kitöltött form adatait elküldik egy queueba, a szerver pedig egy másik üzenettel válaszol erre. Azaz a kliens alapjaiban aszinkron, és a válaszok események formájában jönnek vissza.
A message alapú kommunikáció nagy előnye, hogy az üzeneteket össze lehet nyalábolni, és egyben elküldeni. Így a szerviz lehet finom felbontású, de a kommunikáció mégis gyors, nem sok kis darabból áll. Érthetően ezt szinkron, rpc jellegű szerviz hívásokkal nem lehet megcsinálni.
Ez a fajta queued, service bus alapú gondolkodásmód szokatlan nekem, de nagyon szimpatikus. Van valakinek tapasztalata ilyen rendszer tervezésével? Bármilyen url, pointer, könyv, személyes tapasztalat érdekelne. Úgy érzem nagy dolgokat lehet ezzel összerakni, csak meg kell alaposan értenem.

Még egy gondolat. WCF proxyk használatával az alapban message alapú, asszinkron kérés-válaszokból összeraknak egy RPC jellegű kommunikációt, úgy, hogy a kliens vár a szerver válaszára. Aztán a kliens kedvéért, hogy ne blokkoljuk le a GUIt csinálunk háttérszálat, ahol bevárjuk a szerviz válaszra váró szálat. :)
Miért nem használunk eleve aszinkron üzenetváltásokat, és akkor sokkal egyszerűbb lesz a kép. A kliens bepostázza a kérést a buszra, és megy tovább. Amikor a válasz megjön, akkor meg erről eseményben értesül. Nyilván itt is vannak háttérszálak, hisz ki fogadná akkor a szervertől jövő választ, és ki hívná vissza a kliens eseményeken keresztül, de valahogy akkor is tisztábbnak tűnik a kép, mint az erőltetett RCP-jellegű módszernél. Nem?

.NET fejlesztői álláslehetőség

Monday, April 4th, 2011

Kb. egy hónap múlva elkezdek dolgozni egy igen komplex nagyvállalati enterprise app prototípusán. Ebben pár hónapon keresztül fogok részt venni, viszont valakinek ebből kész terméket is kellene készíteni. Ehhez nyitott meg a megrendelő cég 2 állást, amelyeket alább részletezek.
Ha kedvet érzel .NET-tel, a legmodernebb technológiákkal dolgozni és emberileg is passzol rád amit a követelményekben leírnak, akkor várunk szeretettel.
Az állások már most nyitottak, mivel a velem együtt dolgozzuk ki a prototípust, a cél az, hogy a tartósan a projekten dolgozó emberek mélységében tisztában legyenek azzal, amit tervezek.
Ha érdekel a dolog, az email címemen keresztül jelentkezhetsz.

A két állás:

Termékfejlesztési vezető

Több, mint 10 éve eredményesen működő, nemzetközi háttérrel rendelkező szoftverfejlesztő cég .NET és Oracle technológián alapuló, integrált vállalatirányítási rendszer fejlesztési projektjéhez termékfejlesztési vezető keres főállásban.

Feladat:
• Folyamatban lévő termékfejlesztési projekt vezetésének átvétele, újraszervezése;
• A termék specifikációjának áttekintése és teljessé tétele, a rendszerterv elkészítése;
• A fejlesztési csapat munkájának összehangolása , a termékfejlesztési projekt különböző fázisaiban a projekt céljainak elérése érdekében a megfelelő, felelős szakmai és vezetői döntések meghozatala;
• A projekttel kapcsolatos erőforrás-menedzsment, felelős becslések elkészítése , feladatok kiosztása, megoldások ellenőrzése;
• Fejlesztői csapat vezetése, együttműködés más szakmai vezetőkkel.

Cégünk számára az ideális jelölt:
Informatikai vagy műszaki felsőfokú végzettséggel rendelkezik, tapasztalata van, sikeres .NET-es termékfejlesztési projektekben vezető fejlesztőként/tervezőként, továbbá projektvezetésre alkalmas vezetői készségekkel rendelkezik. Határozott, céltudatos személyiség képes gyors döntések foganatosítására. Stratégiai, üzleti szemlélet jellemzi, képes ’big picture’-ben gondolkodni. Munkája magabiztos elvégzéshez Oracle ismerettel és közép szintű angol nyelvismerettel rendelkezik.

Munkavégzés helye: Budapest

Jelentkezés:
Hosszú távú, kölcsönös együttműködésre alapuló munkakapcsolat kialakítása érdekében várjuk jelentkezését.
Jelentkezését csatolt fényképes magyar és angol nyelvű szakmai önéletrajzzal, motivációs levéllel, referencia megjelölésével az alábbi címen várjuk: zsolt.soczo@gmail.com

A másik:

.NET vezetőfejlesztő

Több, mint 10 éve eredményesen működő, nemzetközi háttérrel rendelkező szoftverfejlesztő cég .NET és Oracle technológián alapuló, integrált vállalatirányítási rendszer fejlesztési projektjéhez vezetőfejlesztőt keres főállásban.

Feladat:
• A senior és junior fejlesztők szakmai irányítása, modultervezés, a feladatok megvalósítása a fejlesztőkkel és riportálás.
• A hozzá rendelt fejlesztők munkájának szakmai irányítása, számukra feladatok szabása és értékelése.
• Termék moduljainak tervezése a fejlesztési munka feladatokra bontása, kiosztása, visszavétele. A specifikációt végző konzulenssel való együttműködés a tervezés érdekében az ügyfél igény pontosítása ügyféllel szükség esetén.
• Döntés a tesztelési feladatokról, együttműködés a tesztelési csoporttal.
• Erőforrásbecslés, a megadott becslések visszaellenőrzése, a becslési folyamat pontosítása.

Cégünk számára az ideális jelölt:
Informatikai vagy műszaki felsőfokú végzettséggel rendelkezik, tapasztalata van, sikeres .NET-es termékfejlesztési projektekben vezető fejlesztőként. Pontos, precíz összehangolt munkavégzésre képes, munkája magabiztos elvégzéshez Oracle ismerettel és közép szintű angol nyelvismerettel rendelkezik.

Munkavégzés helye: Budapest

Jelentkezés:
Hosszú távú, kölcsönös együttműködésre alapuló munkakapcsolat kialakítása érdekében várjuk jelentkezését.
Jelentkezését csatolt fényképes magyar és angol nyelvű szakmai önéletrajzzal, motivációs levéllel, referencia megjelölésével az alábbi címen várjuk: zsolt.soczo@gmail.com

Microsoft Visual Studio 2010 Service Pack 1 letölthető

Wednesday, March 16th, 2011

Még nem néztem, mi van benne, de VS SPknél nem szoktam agyalni, felrakom.

Érdekes .NET perf tapasztalat

Saturday, March 5th, 2011

Amikor profilerrel megnézünk egy .NET kódot sokszor megdöbbentő helyen lesz benne bottleneck.

Az alábbi kód 1% időt visz el egy nagyon processzorintenzív kódban:


if (bar.L == 0)

Ami ebben lassú, az a System.Decimal.op_Implicit(int32). A bar.L egy decimal. Érdekes, mi?
Mi a megoldás? A 0 legyen valóban decimal, de int, amit konvertálni kell:


if (bar.L == 0M)

1% kevés, de sok 1% már számít.

Adding External References to SQL CLR Projects

Friday, February 25th, 2011

Ha egy SQLCLR eljárásból kell meghívni valamilyen külső komponenst.
A trükk az, hogy a külső assembly-t is be kell telepíteni az SQL serverbe CREATE ASSEMBLY-vel, mivel az csak onnan hajlandó betölteni assemblyket (pár fw. alap dllt kivéve).

C# 4 Covariance

Tuesday, February 1st, 2011

.NET 4-es tanfolyamhoz írok egy prezentációt. A co és -contravarianciát próbálom érhetővé tenni. Kb. ez van a slideokon:

Variance annotations – covariance 1.


class Allat { }
class Kutya : Allat { }

interface IAllatGyar<T> where T : Allat
{
    T Create();
}
class AllatGyar<T> : IAllatGyar<T> where T : Allat
{
    public T Create()
    {
        return default(T);
    }
}
AllatGyar<Kutya> kutyagyar = new AllatGyar<Kutya>();
IAllatGyar<Allat> allatGyar = kutyagyar; //cast, jogos?
Allat a = allatGyar.Create(); //mit ad vissza, típusbiztos?

Type ordering
Kutya <: Allat - A Kutya az Allat osztály leszámazottja
k : Kutya - k a Kutya típus egy példánya
Ha k : Kutya és Kutya <: Allat, akkor k : Allat (Liskov féle helyettesítési elv)
Igaz-e, hogy ha Kutya <: Allat, akkor IAllatgyar< Kutya > <: IAllatgyar< Allat > ?
Egy Kutya példány implicit castolható Allattá. Az Allatgyar< Kutya > típusbiztosan castolható-e Allatgyar< Allat >-tá?
Ha csak kimeneti paraméterként vagy visszatérési értékként jön ki T, akkor igen, mert Kutya <: Allat, így minden kimeneti paraméternél a Allat referenciával biztonságosan elérhető egy leszármazott Kutya példány is.
Ha igen, akkor T covariant, mert a típusparaméterek type orderingje érvényes a típust használó generikus típusra is, ugyanabban a sorrendben (Kutya <: Allat ==> IAllatgyar< Kutya > <: IAllatgyar< Allat >).
C# 4-ben az interfész metódus vagy delegate szignatúrában az out kulcsszó jelzi ezt:


interface IAllatgyar<out T>.

Amikor ez nem megy:


class Allat { }
class Kutya : Allat { }

interface IAllatGyar<T> where T : Allat
{
    T Create();
    void Valami(T t); //T befelé megy!
}

AllatGyar<Kutya> kutyagyar = new AllatGyar<Kutya>();
IAllatGyar<Allat> allatGyar = kutyagyar;

kutyagyar.Valami(new Kutya()); //Ez nyilván ok

allatGyar.Valami(new Lo());    //És ez???

Ha bemeneti paraméter is T, akkor az IAllatgyar< Allat > statikus típuson, amely valójában a IAllatgyar< Kutya > dinamikus típusra mutat átadható lenne más állat is, pl. Ló, amely szintén Allat leszármazott, de az nyilvánvaló runtime hibát okozna. Ezért nem lehet covariant T, ha az interfészen bemenetként is szerepel T.

Érhető ez így? Bármilyen javaslatot szívesen fogadok. A delegatekhez is írok persze anyagot, ez csak az eleje.

Csúnya multithreading hiba

Friday, January 21st, 2011

Double checked lockingnak indult, de bug lett belőle. Mit rontottam el?


private static volatile Dictionary<DateTime, Pair<TimeSpan>> holidayDays;
private static readonly object staticLock = new object();

private Dictionary<DateTime, Pair<TimeSpan>> GetHolidayDays()
{
    if (holidayDays == null)
    {
        lock (staticLock)
        {
            if (holidayDays == null)
            {
                holidayDays = new Dictionary<DateTime, Pair<TimeSpan>>();
                FillTradingHours(holidayDays, "HOL");
            }
        }
    }
    return holidayDays;
}

Mi a hiba ebben?

Friday, December 17th, 2010

http://www.dofactory.com/Patterns/PatternSingleton.aspx

A mellékelt példakódban valami nem igaz. Mi?

.NET Stringek lementése Memory Dumpból

Friday, November 26th, 2010

Mostanában elég sokat turkálok problémás webappok dumpjában. Leírom magamnak is, hogy lehet lementeni .NET stringeket a dumpból.
WinDbg dolgok következnek.

A nagy stringeket kilistáztatom a
!DumpHeap -min 100000 -type System.String
paranccsal.

Valamelyik heapről kinézek magamnak egyet, és az előbbi parancs kimenetének első oszlopában található címet felhasználva belenézek a du cím paranccsal.
Pl.
0:000> du 5ce31140
5ce31140 “*****<sitecore database=”SqlSer”
5ce31180 “ver”>.. <sc.variable name=”da”

Az elején a kuszaság (átírtam csillagokra, mert elrontotta a htmlt) a .NET Stringek adminisztrációja és az object header.
Ha szemre tetszik a string, akkor pl. ki akarom menteni fájlba.
Nézzük meg a szöveges rész előtti bináris részt (dd).

0:000> dd 5ce31140
5ce31140 793308ec 00040001 0002836c 0073003c
Az első 8 byte az object header (32 biten, 64-en ez asszem 16 byte), sync block és type leíró. Számunkra ez érdektelen. A 3. dword már érdekesebb, ez a string hozza karakterekben. Azaz bájtban ennek a duplája, mert 2 bytes unicode ábrázolást használ a .net.
Így stringünk hossza 0002836c*2 byte. A 0073003c már a < karakter (003c) és az s betű (0073), szokásos fordított Intel sorrendben.
A szöveges tartalom tehát a 5ce31140+0c címen kezdődik (headert átlépjük), és 0002836c*2 a hossza.
A tartalom fájlba írása már egyszerű:
.writemem c:\temp\s1.txt 5ce31140+0c L0002836c*2

Kedvencem a WinDbg, de ezt már mondtam. :)

Blocking read kiváltása mivel?

Friday, July 2nd, 2010

Tegyük fel írok egy tcp kliens programot, TcpClient, NetworkStream és társaival. A NetworkStream.Read blokkoló módon működik. Nekem az kell, hogy bármikor tudjam abortálni a tcp csatornát. A Read ha miatta beragad az egy szál, az Thread.Abort állítja le (igaz, az Thread.Interruptot még nem próbáltam).

Lehetséges megoldásként az async BeginReadet javasolják, de azzal meg az a bajom, hogy minden kis darab olvasása után egy waithandlere kell várni, ami meg context switchet eredményez, így a nagysebességű időszakokban belassít.
Mi vajon a korrekt megoldás, ami megszakítható és gyors is?

Access to modified closure figyelmeztetés a Resharperben

Thursday, June 24th, 2010

Már ez önmagában megéri a termék árát, máskülönben sok órát lehet debugolni a probléma miatt.

Alább a langId változó bevezetését javasolta, okkal, másképp a variable capturing beszopat. De csúnyán.


foreach (var lang in languages)
{
    var langId = lang.Value.ID;
    resStringLookup[lang.Key] = new CachedEntityLookup<ResString, int, string>(
        rs => rs.ResStringIntID, //Kulcs a resid
        rs => rs.TransText,     //A tartalom a lokalizált szöveg
        rs => rs.LanguageID == langId);  //Ehhez a nyelvhez építjük fel a táblát
}

Best Practices: How to implement INotifyPropertyChanged right?

Thursday, June 17th, 2010

Jó összefoglaló a témában.

Update: ez lett a vége:


using System.ComponentModel;
using System.Threading;
using Krs.Ats.IBNet;

namespace ATS.IB
{
    /// <summary>
    /// Real-time data descriptor for IB tick data
    /// </summary>
    public class MarketData : INotifyPropertyChanged
    {
        public Contract IBContract { get; set; }
        public Ticker Ticker { get; set; }

        private decimal lastPrice;
        public decimal LastPrice
        {
            get { return lastPrice; }
            set
            {
                lastPrice = value;
                OnPropertyChanged(LastPriceChangedArgs);
            }
        }

        private decimal lastBid;
        public decimal LastBid
        {
            get { return lastBid; }
            set
            {
                lastBid = value;
                OnPropertyChanged(LastBidChangedArgs);
            }
        }

        private decimal lastAsk;
        public decimal LastAsk
        {
            get { return lastAsk; }
            set
            {
                lastAsk = value;
                OnPropertyChanged(LastAskChangedArgs);
            }
        }

        private int lastSize;
        public int LastSize
        {
            get { return lastSize; }
            set
            {
                lastSize = value;
                OnPropertyChanged(LastSizeChangedArgs);
            }
        }

        private int lastAskSize;
        public int LastAskSize
        {
            get { return lastAskSize; }
            set
            {
                lastAskSize = value;
                OnPropertyChanged(LastAskSizeChangedArgs);
            }
        }

        private int lastBidSize;
        public int LastBidSize
        {
            get { return lastBidSize; }
            set
            {
                lastBidSize = value;
                OnPropertyChanged(LastBisSizeChangedArgs);
            }
        }

        private static readonly PropertyChangedEventArgs LastPriceChangedArgs = ObservableHelper.CreateArgs<MarketData>(x => x.LastPrice);
        private static readonly PropertyChangedEventArgs LastBidChangedArgs = ObservableHelper.CreateArgs<MarketData>(x => x.LastBid);
        private static readonly PropertyChangedEventArgs LastAskChangedArgs = ObservableHelper.CreateArgs<MarketData>(x => x.LastAsk);
        private static readonly PropertyChangedEventArgs LastSizeChangedArgs = ObservableHelper.CreateArgs<MarketData>(x => x.LastSize);
        private static readonly PropertyChangedEventArgs LastBisSizeChangedArgs = ObservableHelper.CreateArgs<MarketData>(x => x.LastBidSize);
        private static readonly PropertyChangedEventArgs LastAskSizeChangedArgs = ObservableHelper.CreateArgs<MarketData>(x => x.LastAskSize);

        private void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            var eventHandler = PropertyChanged;
            if (eventHandler != null)
            {
                if (guiSyncContext != SynchronizationContext.Current)
                {
                    guiSyncContext.CallOnMainThread(OnPropertyChanged, e);
                }
                else
                {
                    eventHandler(this, e);
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private SynchronizationContext guiSyncContext = SynchronizationContext.Current;

        public void SetGuiSyncContext()
        {
            guiSyncContext = SynchronizationContext.Current;
        }
    }
}

Visual Studio unit teszt profilozás

Monday, May 17th, 2010

A unit tesztek kiváló sebességmérési célok lehetnek, mivel kimagozottan futtatnak egy adott kódrészletet. A unit teszten jobb gomb, create performace session. Zseniális, csak nem megy, ha 64 bitesre van állítva a unit teszt host. Nem láttam ledokumentálva (vagy csak nálam nem megy ez).
Egyszerűen soha nem ér véget a tesztelés, beragad a profiler session.

Dynamic sebesség újra

Monday, May 17th, 2010

Hogy ne a levegőbe beszéljek:


using System;
using System.Diagnostics;
using System.Reflection;

namespace DynamicTypeTest
{
    class Program
    {
        static void Main(string[] args)
        {
            object target = "alma";
            object arg = "m";

            string a2 = (string)arg;

            Stopwatch w = Stopwatch.StartNew();

            const int callNumber = 1000 * 1000;
            for (int i = 0; i < callNumber; i++)
            {
                Type[] argTypes = new Type[] { typeof(string) };
                MethodInfo mi = target.GetType().GetMethod("Contains", argTypes);
                object[] oa = new object[] { a2 };
                bool b = (bool)mi.Invoke(target, oa);
            }

            w.Stop();
            Console.WriteLine("Reflection hívási idő: {0}", w.Elapsed);
            double elapsedTickForReflection = w.ElapsedTicks;

            w.Restart();

            for (int i = 0; i < callNumber; i++)
            {
                bool b = ((dynamic)target).Contains(a2);
            }

            w.Stop();
            Console.WriteLine("Dynamic hívási idő: {0}", w.Elapsed);

            Console.WriteLine("A dynamic {0}x gyorsabb volt.", elapsedTickForReflection / w.ElapsedTicks);
        }
    }
}

Reflection hívási idő: 00:00:02.5393161
Dynamic hívási idő: 00:00:00.2049100
A dynamic 12.3923444658829x gyorsabb volt.

Ha ügyesebbek vagyunk, és kivesszük a ciklusból a reflection előkészítését:


using System;
using System.Diagnostics;
using System.Reflection;

namespace DynamicTypeTest
{
    class Program
    {
        static void Main(string[] args)
        {
            object target = "alma";
            object arg = "m";

            string a2 = (string)arg;

            Stopwatch w = Stopwatch.StartNew();

            Type[] argTypes = new Type[] { typeof(string) };
            MethodInfo mi = target.GetType().GetMethod("Contains", argTypes);
            object[] oa = new object[] { a2 };

            const int callNumber = 1000 * 1000;
            for (int i = 0; i < callNumber; i++)
            {
                bool b = (bool)mi.Invoke(target, oa);
            }

            w.Stop();
            Console.WriteLine("Reflection hívási idő: {0}", w.Elapsed);
            double elapsedTickForReflection = w.ElapsedTicks;

            w.Restart();

            for (int i = 0; i < callNumber; i++)
            {
                bool b = ((dynamic)target).Contains(a2);
            }

            w.Stop();
            Console.WriteLine("Dynamic hívási idő: {0}", w.Elapsed);

            Console.WriteLine("A dynamic {0}x gyorsabb volt.", elapsedTickForReflection / w.ElapsedTicks);
        }
    }
}

Reflection hívási idő: 00:00:01.2058747
Dynamic hívási idő: 00:00:00.2044023
A dynamic 5.89951388765798x gyorsabb volt.

Jó ez, szeretjük, pedig nem is COMolunk.

Miért szeretem a dynamic típust reflection helyett?

Monday, May 17th, 2010

Ezért:


var allEntities = (IEnumerable)reposType.GetMethod("GetAll", new Type[] { typeof(string[]) }).Invoke(repos, new object[] { includes });

vs.


var allEntities = (IEnumerable)repos.GetAll(includes);

Emellett a dynamic vagy 10x gyorsabb, még akkor is, ha a reflectionnél cachelem a típusleírókat.

Mi hiányzik a Visual Studioból Resharper nélkül?

Monday, May 17th, 2010

Pár napja nem megy a Resharprem, azóta olyan dolgozni a VS-val, mintha notepad előtt ülnék. Fel nem tudom sorolni azt a sok dolgot, amivel segít kódírás közben, pár dolog csak mintaképp:
Refactoring:
Inline, Pull members up és down, Safe delete, Convert Property to Method és vissza, related itemek átnevezése is, make local variable, field vagy parameter (ezeket nagyon sokat használtam), change signature.
Egyebek: interfész metódus implementáció ahogy létrehoztam egy interface metódust (más mint a beépített), initialize field from contructor, create field from constructor parameter, automatikus base felhívások, var vs. típusos deklaráció konverzió, for to foreach és vissza, foreach to LINQ (durva), lambda expression, lambda statement, anon method, sima method konverziók, automata delegate-re passzoló metódus létrehozás, collapse all a solution explorerben, CTRL-T-re kódfájl keresés (nagyobb solution esetén életmentő), intellisense még nem létező, de már használt változókra, statikus class generálás, ezerféle kódelemzés, enumokhoz jobb intellisense, MVC-hez parser, stb.
Amióta nem megy, sokkal többet kell lapozgatnom a kódfájlok között, időpazarlás.
El se tudom képzelni már, hogy tudnék nélküle programozni, ennyire addict még semmilyen programtól nem lettem.
Ha az msnek lenne esze, megvenné a céget, többet ér, mint a Yahoo. :)

Parallel Stacks a VS 2010-ben

Thursday, May 13th, 2010

Jó ez a VS 2010. Belefutottam egy problémába, amiben a Parallel stack segítsége jól jött.

Amint a képen látható az egyik szál bejár egy Dictionary-t serializálás miatt, miközben a másik beleenyúl, ettől aztán elszakad a cérna az iterátornál. Látható a képen, hogy két SaveSettings egyszerre fut, de csak az egyik seralizál, a másik, a jobbról látható vár, mert raktam be lockot.
Igen, ám, de rossz helyre! A kollekciót engedem módosítani (this[string].set), mert az a lockoláson kívül esik. Azaz a probléma a rosszul megválasztott zárolási szint (lock scope). Egy metódushívással kijjebb kell rakni, az indexerbe.

Coverage fejtörő

Wednesday, May 12th, 2010

A VS coverage-e ezt mutatja, hogy ez a sor csak részben van lefedve:


return (GetSourceItem(step) - this[step - 1]) * e + this[step - 1];

Nincs benne && vagy ||, akkor triviális lenne. Én már tudom a választ. :)

Update: alul, kommentben ott a megoldás.