Welcome to MSDN Blogs Sign in | Join | Help

News


  • Social networking. Multiple personas, multiple success by t.o.g.i.o.t.i.t.


    blog author contact page (Polish)

    My blogger code: B7 d t k+ s++ u-- f i o x e+ l c-
    Add to Technorati Favorites
    My Blog Juice


[PL] Gamedev w Hollywood, Hollywood w gamedev

W branży rozrywkowej kwestia video (filmy, seriale, tv shows, itd) coraz bardziej zlewa mi się z tym co w wersji interaktywnej reprezentują sobą gry.
Kiedyś dużo było o interaktywnych filmach, telewizji i tak dalej. Cyberpunk nadciąga i tak jak obserwuję firmy coraz bardziej przenikają pomiędzy swoimi poletkami.

Od jakiegoś czasu nie dziwią mnie gry sygnowane znakiem Warner Bros.;  Monolith czy Vivendi Universal.

W drugą stronę też od czasu do czasu ktoś kupi prawa do ekranizacji jakiejś gry, ale naogół nie wychodziło to do tej pory zbyt dobrze (poza nielicznymi przypadkami).
Teraz przeczytałem coś co mnie bardzo zaciekawiło. Gigant w branży - Electronic Arts - planuje zakupy jeszcze bliżej Hollywood, aby lepiej spożytkować swoje IP (Intelectual Property) w formie filmów i/lub seriali.

Hoho..

[PL] C# 4.0 - czwarta zasada dynamiki

Na Channel 9 macie ciekawy webcast z twórcami języka C# i wieloma innymi architektami stojącymi za .NET Framework.
Opowiadają o chyba oczywistym kierunku w którym język i platforma będą się rozwijać dalej.
Poniżej filmik:

C# 4.0: Meet the Design Team


[PL] Własny dostawca w Linq (dla opornych) - cz. 4

Artykuł został rozbity na wiele części, poniżej spis treści:
I.  Budowa zapytania
II. Podstawy analizy drzewa wyrażeń
III. Właściwa analiza drzewa wyrażeń
IV. Pobieranie i zwrot danych

Pobieranie i zwrot danych

W poprzednich częściach omówiliśmy sobie podstawy konstrukcji naszego własnego dostawcy do Linq. Powinnyśmy już wiedzieć, że filary opierają się na implementacji dwóch interfejsów IQueryable oraz IQueryProvider. Ich implementacja rozkłada się w zasadzie na dwie części. Jedna to odpowiednia interpretacja dostarczonego już drzewa wyrażeń pochodzącego z zapytania Linq. Pomysł jak je poprawnie zanalizować i przetworzyć, np. na zapytanie SQL (w ciągu znaków) dałem w poprzedniej części.

Jeżeli założę, że ten etap mamy zrobiony to do kompletu nie pozostaje już nic innego jak poprawny zwrot danych zgodny z oczekiwanym formatem. Tym zagadnieniem zajmę się w tej części.

Do tej pory stworzyliśmy parę klas i ich metod, które miały generyczny parametr. Ten parametr naogół wiązał się typem zwracanego obiektu. W drugiej części tego artykułu przedstawiłem wam tymczasowy fragment kodu:

        protected object getResult(string sqlQuery)
        {
            Customer cust = new Customer(); 
            //tu jeszcze nic nie robimy
            //Customer ze względu na bieżacy stan przykładu
            //jest tutaj hardcode'owanym typem zwrotnym 
            return cust;
        }

W żaden sposób nie spełnia on warunku, aby zwrócić generyczny typ o jaki go poprosimy w naszym "jakimkolwiek" zapytaniu. W omawianym przykładzie był to Customer, wcale przecież tak nie musi być. Ba.. nawet jeśli operujemy na typie Customer i nasze proste zapytanie:

var result = (from c in q
      where c.Age > 10
     
select c);

Zaczniemy badać pod kątem dostępnych metod rozszerzających to jaki typ zwrotny oczekują od generycznych metod z IQueryProvider::Execute() to się okaże, że:
* result.First(); powinien nam zwrócić typ Customer
* result.Count(); powinien nam zwrócić typ Int32;
* result.Any(); powinen nam zwrócić typ bool, i słusznie bo to nic innego jak

{ return result.Count > 0 ? true : false; }

Zatem gdybym miał naszą metodę getResult zaimplementować naprawdę generycznie trzeba się chwilkę zastanowić. Ja w swoim przypadku posłużym się dalej swoją na razie wciąż tymczasowo zaprojektowaną klasą QueryExecutionPlan. Wygląda sobie ona mniej więcej tak:

    public class QueryExecutionPlan
    {        
        public QueryExecutionPlan()
        {...
        public string QueryString;
//gotowy SQL do wykorzystania, np. w SqlCommand
        public QueryResultTypes QueryResultType;
//typ zwracanego rekordu
        public QueryAggregateType AggregateType;
//typ agregatu jeśli występuje
        public String AggregateKeyColumn;
//kluczowa kolumna przy agregatach 

        public Type ReturnType;
//podstawowy typ zwracanego rekordu
        public Type QueryType;
//konkretny typ generycznego Query<T>

        public bool Validate();
//sprawdzanie poprawności stworzonego planu
    }

QueryResultTypes oraz QueryAggregateType to enumeratory na ten moment wyglądające tak:

    public enum QueryResultTypes
    {
        Resultset, //enumerator
        SingleRecord, //pojedyncza instancja rekordu
        Aggregate //wartości numeryczne, np: max,min,count,sum, itd

        IfEmpty //test czy rezultat zwraca jakikolwiek wynik
    }

    public enum QueryAggregateType
    {
        Count, Sum, Min, Max
    }

Idea jest prosta. W przypadku naszego powyższego zapytania Linq, oczekuję w QueryString = "select c.* from Customers c where c.Age>10". W przypadku wykonania funkcji Any, Count, Max, Min oczekuje, że odpowiednie dodatkowe parametry zostaną przekazane w odpowiednich właściwościach. Mój QueryTranslator z drzewa wyrażeń powinien mi to dostarczyć i wtedy odczytywanie rekordów mógę zacząć od następującego ruchu:

Zmieniam trochę swoją klasę dostawcy, teraz jest to abstrakcyjna podstawowa klasa BaseQueryProvider:

    public abstract class BaseQueryProvider : IQueryProvider
    {
        public IQueryable<T> CreateQuery<T>(Expression expression)
        {…}

        public IQueryable CreateQuery(Expression expression)
        {…}

        public TRes Execute<TRes>(Expression expression)
        {
            return (TRes)this.Execute(expression);
        }

        public object Execute(Expression expression)
        {
            QueryExecutionPlan execPlan = null;
            execPlan = Translate(expression);
            return RetrieveResults(execPlan);
        }

        protected abstract QueryExecutionPlan Translate(
              Expression expression);
        protected abstract object RetrieveResults(QueryExecutionPlan plan);

    }

Implementacja CreateQuery się nie zmieniła, a w Execute drobna kosmetyka w stosunku do tego co pokazałem wcześniej. Na podstawie tej bazowej klasy zrobiłem sobie właściwego dostawce, który jak już wspomniałem wcześniej docelowo ma służyć do obsługi wielu fizycznych typów źródeł danych. Zatem mamy MultiSourceQueryProvider:

   public class MultiSourceQueryProvider : BaseQueryProvider
    {
        public MultiSourceConfiguration Configuration
        {
            get;
            set;       
        }

        public MultiSourceQueryProvider(MultiSourceConfiguration config)
        {
            this.Configuration = config;
        }

        public override QueryExecutionPlan Translate(Expression expression)
        {
            switch (Configuration.Type)
            {
                case MultiSourceType.SQLServer:                    
                    return translateToSQLServer(expression);
                case MultiSourceType.Oracle:
                    return translateToOracle(expression);
                case MultiSourceType.File:
                    return translateToFile(expression);
            }

            throw new NotImplementedException("No valid source type provided!");
       

        protected override object RetrieveResults(QueryExecutionPlan plan)
        {
            switch (Configuration.Type)
            {
                case MultiSourceType.SQLServer:
                    return retrieveFromSQLServer(plan);
                case MultiSourceType.Oracle:
                    return retrieveFromOracle(plan);
                case MultiSourceType.File:
                    return retrieveFromFile(plan);
            }

            throw new NotImplementedException("Cannot retrieve data from this source!”);
        } 
    }

Jak widać powyższa klasa nie jest kompletna. Brakuje definicji konfiguracji oraz implementacji poszczególnych metod translateTo* oraz retrieveFrom*
O tym za moment, to na co warto zwrócić uwagę to fakt, że trochę sztucznie ograniczyłem możliwość dalszego rozszerzania tej klasy. Jeśli za moment wpadlibyśmy na moment, że chcemy też wspierać mySQL czy cokolwiek innego to trzeba się dogrzebać do tej klasy i rozbudować switch/case w obu przypadkach. Może lepiej by było dodać dwa typy obiektów - BaseTranslator oraz BaseRetriever, które tutaj były by przekazywane w liście, mogłby by być dodawane nawet w runtime'ie jako pluginy, cokolwiek. Jest to już rozważanie czysto architektoniczne, na razie jako taki zalążek do wieloźródłowego dostawcy Linq mam.

Co dalej? W przypadku translate sprawa jest prosta, już mamy naszego QueryTranslator<T>, który dostarcza nam odpowiednio spreparowany plan wykonania (omówione w cz. 3). Teraz ostatni element, dla przykładu retrieveFromSQLServer().

To co napewno musimy mieć to połączenie do bazy. Tutaj nie ucieknę od starego dobrego Ado.Net:

            IDataReader dataReader = null;
           
SqlConnection conn = new SqlConnection(Configuration.ConfigurationString);
            SqlCommand cmd = new SqlCommand(plan.QueryString,conn);
            conn.Open();
            dataReader = cmd.ExecuteReader();

no i mamy IDataReader. Teraz bardzo chętnie bym sprawdził czy dane i struktura schowana w tym readerze jest zgodna z oczekiwanym typem zwrotnym. Zatem chwila na refleksję :). Oczywiści chodzi mi o System.Reflection. W przypadku gdy mamy zwrócić jeden rekord typu Customer (np. resultset.First()) sprawa wyglądała by mniej więcej tak:

Mamy System.Type naszego Customer ukryte w QueryExecutionPlan.ReturnType;
W tym typie mamy zaszyta informację na temat publicznych pól jakie zawiera poprzez:

FieldInfo[] fields = type.GetFields();

W FieldInfo mamy informacje o nazwie i typie każdego z nich. Zatem na początek sprawdziłbym zgodność pomiędzy tą tablicą a tą zawartą w readerze ala:

            for (int i = 0; i < reader.FieldCount; i++)
            {
                 … reader.GetName(i);
                 … reader.GetFieldType(i);

            }

Mając już pewność, że mamy po obustronnach zgodność, że żadne "mandatory" pole potrzebne do stworzenia obiektu nie zaginęło w zwróconym wyniku możemy sobie spokojnie skonstruować taki obiekcik. Całość w osobnej metodzie zamknąłem w takim kodzie:

        public override IEnumerable ProcessInputData()

        { 
           
bool ok = ValidateSourceAndDestination(reader);
            FieldInfo[] fields = plan.ReturnType.GetFields();

            if (ok)
            {
                while (reader.Read())
                {
                    object instance =
                       Activator.CreateInstance(plan.ReturnType);
                    for (int i = 0; i < reader.FieldCount; i++)
                    {
                        FieldInfo fi =
                            (from f in fields
                            where f.Name.ToLower()
                                 == reader.GetName(i).ToLower()
                            select f).First();
                        fi.SetValue(instance, reader.GetValue(i));
                    }
                    yield return instance;
                }
            }
         }

No i mamy niby komplet. Teraz powyższy zlepek idei i kodu należy zebrać w jeden projekt, wypieścić, skompilować i mamy własnego dostawcę do Linq.

Pytanie tylko czyżby? Zakładam, że już w pełni interpretujemy drzewo wyrażeń i doskonale zoptymalizowaliśmy nasze zapytanie. Przekazaliśmy je do naszych fizycznych źródeł danych i zwracamy zgodnie z oczekiwanym formatem to ciągle mi brakuje jednej, kolejnej dużej rzeczy, która ściśle łaczy się z sensem wykorzystania ORM - pracy na metamodelach.

W tym czterech częściach praktycznie w ogóle o nim nie wspomniałem, a jest moim zdaniem następnym solidnym krokiem w zabawie.

Podsumowując: Nie dałem wam konkretnego gotowego i działającego przykładu, ale wydaje mi się, że dostarczyłem gotowego pomysłu jak takowego dostawcę stworzyć. Pozostaje jeszcze dużo niewiadomych na dalszych etapach, do których zapewne w następnych wpisach wrócę. Jednym z nich jest jak wspomniałem metamodel. Inne tematy to kwestia zapisu i transakcji, która w powyższych rozważaniach też nie została zupełnie uchwycona.
Co na temat Linq w trójwarstwówce i "plucie" zapytaniami do serwera aplikacyjnego?
To jak już akumulujemy pewne informacje na takowym serwerze to może warto pomyśleć o cache'u zapytań. Może warto dodać do tego workflow już na etapie konstrukcji metamodeli?

Wierzę, że tematów i zagadnień można sobie mnożyć. Osobiście nie wierzę, że ten temat da się w jakikolwiek sposób wyczerpać, więc aż się dziwie, że nie ma jeszcze żadnych komentarzy. :)

[PL] Rok zamknięty z lekką górką - czas na piknik?

Nie wszyscy pewnie wiedzą, ale w świecie Microsoftu istnieje wyraźne rozdzielenie pomiędzy rokiem kalendarzowym (CY) a rokiem fiskalnym (FY). Tym czym operujemy realizując nasze cele, od małych do tych globalnych na które patrzą inwestorzy z Wall Street, zamyka się właśnie w roku fiskalnym.

Lata fiskalne w MS rozpoczynają się 1 lipca danego roku i kończą się ostatniego czerwca roku następnego. Właśnie zakończyliśmy FY08, teraz zaczyna się FY09.

Wiem, że niektórzy z was są świadomi, bo z takich miłych i sympatycznych choć niestandardowych życzeń jakie ostatnio dostałem na maila były życzenia noworoczne z okazji nowego roku fiskalnego :)

W każdym razie FY08 się skończył i Microsoft opublikował swoje wyniki finansowe w zamkniętym już roku. Dostępne są tutaj:
http://www.microsoft.com/msft/earnings/FY08/earn_rel_q4_08.mspx. Rok udało się zamknąć z wynikiem $60.42B, czyli po naszemu 60 miliardów dolarów. Rok wcześniej osiągneliśmy wynik $51B, czyli krótki mówiąc mój pracodawca ciągle rośnie.

Jaki to ma wpływ na mnie i na moją pracę? Bezpośrednio pewnie nijak. Pośrednio tyle, że firma raczej dalej będzie agresywnie inwestować niż ciąć koszta - więc prace pewnie jeszcze też będę miał. Polski Microsoft także bardzo dynamicznie się rozwija, tak jak patrzę po ilości osób w biurze teraz, a ilu nas było w 2005 roku kiedy zaczynałem (i ilu osób kompletnie nie rozpoznaje, kiedy wcześniej miałem przynajmniej mgliste wyobrażenie jak się osoba nazywa, czym zajmuje, albo przynajmniej w którym jest dziale).

W każdym razie, swoje drobniejsze cele, które w jakiś tam sposób mam nadzieję na ten wynik się przekładają też zrealizowałem, co więcej muszę przyznać, że uwielbiam pracę z partnerami ISV w Polsce i mam nadzieję, że to co udało się w tym roku z mojej strony zapoczątkować w następnych latach będę skutecznie rozwijał, aby poziom współpracy także rósł. W tym roku, który się skończył większość swojej energii poświęcałem na to aby przekazywać wiedzę technologiczną partnerom w kontekście konkretnych projektów albo wizji projektów. Dużo z tych inicjatyw w tym momencie po waszej stronie jest cały czas w developmencie. Część już jest dostępna na rynku, albo lada moment będzie, więć jedno z bonusowych założeń jakie sam sobie obiecałem w tym nadchodzącym roku to zadbać o to, aby nie tylko te rozwiązania i aplikacje udało się skończyć i wprowadzić na rynek, ale i żeby były jak najlepiej widoczne.
Napewno będę się też starał pomóc wam w kompatybilności waszych aplikacji z najnowszymi produktami Microsoft jak: Windows Vista, Windows Server 2008 czy Office System. Więc jeśli potrzebujecie takiej pomocy to nie czekajcie aż do was dotrę, skontaktujcie się ze mną pierwsi.
Kolejne z działań jakie planuję na przyszły rok to oczywiście dalsza praca u podstaw w przekazywaniu wiedzy i informacji na temat najnowszych i niedługo nadchodzących technologii i produktów Microsoft.
Po wakacjach będzie MTS (Microsoft Technology Summit) 2008. Będę na tej konferencji, napewno będę opowiadał o platformie Dynamics, z perspektywy dewelopera. Co więcej, nie będę zdradzał. Zapraszam do śledzenia strony konferencji, wiadomości są przekazywane na bieżąco.
Generalnie FY09 zapowiada się bardzo interesująco już z tych informacji, którymi dysponuję w tym momencie. Praktyka zweryfikuje. Na ten moment jednak powoli się szykuję do wakacji i krótkiego odpoczynku na doładowanie baterii.

Od końca sierpnia zaś już coraz bardziej z pełną parą zabiorę się wykonywanie planów na FY09 i codzienną współpracę z partnerami ISV. Howgh!

[PL] Własny dostawca w LINQ (dla opornych) - cz. 3

Artykuł został rozbity na wiele części, poniżej spis treści:
I.  Budowa zapytania
II. Podstawy analizy drzewa wyrażeń
III. Właściwa analiza drzewa wyrażeń
IV. Pobieranie i zwrot danych

Właściwa analiza drzewa wyrażeń

W poprzedniej części wprowadziłem temat drzewa wyrażeń zwracanego poprzez uniwersalny typ Expression. Wierzę jednak, że zawarte tam informacje poprzez ich chwilową niekompletność mogą wprowadzić więcej zamieszania niż wyjaśnienia. Ta część powinna umożliwić wam napisanie translatora uwzględniającego chociażby najprostsze scenariusze wykorzystania zapytań Linq.

Nasze status quo na ten moment to stworzona klasa QueryTranslator, której zadaniem jest przetworzenie drzewa wyrażeń na ciąg znaków zgodny z językiem SQL. Aby ułatwić zabawę poprzednio omówioną wersję trochę zrefaktoryzowałem (uwielbiam te kalki językowe
J). Aktualny jej stan to:

    internal class QueryTranslator<T>
    {
        QueryExecutionPlan queryExecPlan;
        public QueryTranslator()
        { … }

        public QueryExecutionPlan Translate(Expression expression)
        {
            queryExecPlan = new QueryExecutionPlan();
            queryExecPlan.ReturnType = typeof(T);
            queryExecPlan.QueryType = typeof(Query<T>);           

            Expression returnExpression =expression;
            do
            {
                returnExpression = analyzeExpressionTree(returnExpression);
            } while (returnExpression != null);
            return queryExecPlan;
        }

        private Expression analyzeExpressionTree(Expression expression)
        {
            if (expression == null)
                return null;
            Expression ret = null;
            switch (expression.NodeType)
            {
                case ExpressionType.Add:
                case ExpressionType.AddChecked:
                case ExpressionType.And:
                
                case WSZYSTKIE_ExpressionType:
                
                case ExpressionType.Subtract:
                case ExpressionType.SubtractChecked:
                case ExpressionType.TypeAs:
                case ExpressionType.TypeIs:
                case ExpressionType.UnaryPlus:
                    //tu ma być realny kod analizujący wyrażenie
                    break;               

default:
                    throw new NotImplementedException("QueryExecutionPlan does not support used type of expression: " + expression.NodeType.ToString());
     }
     return null;
}

    }

Aby nie wydłużać powyższego fragmentu kodu wyciąłem komplet przypadków do switcha, pozostawiając tylko parę, aby pokazać wam szerszy obraz. W realnym kodzie są wszystkie i wszystkie w ten czy inny sposób musimy uwzględnić. Patrząc po ExpressionType możemy zobaczyć wszystkie rodzaje zapytań jakie wspiera składnia Linq.

W poprzedniej części obiecałem przyjrzeć się dokładniej, co ExpressionType zawiera i jakie to ma odniesienie do wszelakich klas pochodnych od Expression. Pełny opis wszystkich wyliczeń tego typu jest dostępny na MSDN:
http://msdn.microsoft.com/en-us/library/bb361179.aspx
Konfrontując ich liczbę z liczbą klas dziedziczących po Expression widać, że przy analizie wypadałoby zrobić pewną agregację. Tak dla przykładu patrząc po opisie UnaryExpression na MSDN, ten typ wyrażenia zwracany jest w przypadku ExpressionType o wartościach:
Negate, NegateChecked, Not, Convert, ConvertChecked, ArrayLength, Quote, TypeAs. Przeglądając wszystkie typy Expression i wartości numeratora, jakie wspierają warto powyższego switcha pogrupować tak, aby odpowiednie typy ExpressionType były obsługiwane przez jednego wyspacjelizowanego case’a.  Gotowy przykład klasy, która odpowiednio analizuje takie drzewo jest dostępny czy na blogu Matt’a Warrena, czy też w artykule na Code guru napisanym przez Jacka Matulewskiego. Klasa ExpressionVisitor opisana tam zawiera dosyć znaczącą liczbę niezbyt przejrzystego kodu, więc aby umożliwić sobie lekkie wprowadzenie do poprawnej analizy drzewa wyrażeń zachęcam na początek przy prostych przykładach zapytań implementować poszczególne typy ExpressionType jakie lądują, np. w powyższej metodzie analyzeExpressionTree. W przypadku naszego prostego zapytania:

                var result = (from c in Customers
                              where c.Age > 10
                              select c);

drzewo powinno wyglądać następująco:

image 
Luźno z takiego drzewa można spróbować złożyć „select * from Customers c where c.Age>10”. Gdybyśmy do naszego kodu Linq dodali First(). To zanim wystąpił by nasz Call(Where) wystąpiłby Call(First). W SQL przełożyć to możemy na „select top 1 * from Customers c where c.Age>10”

Gdybym nasze zapytanie zmodyfikował tak, aby nie zwracać całego Customer:

               
var result = (from c in Customers
                              where c.Age > 10
                              select c.FirstName).First();

Wtedy ścieżka wyglądała by tak:
1) Call (First)
2) Call (Select)
3) Call (Where)
.. a dalej już jak na powyższym rysunku.

Poprawna interpretacja MethodCallExpression dla metody „Select” powinna nas doprowadzić do oczywistej interpretacji czyli: „select c.FirstName from customers c where c.Age>10”

Przekładanie powyższego drzewa na ciąg znaków z kodem SQL najlepiej przetwarzać na początku przez StringBuilder (tak jak to ma miejsce w przypadku ExpressionVisitor).
Ja powyżej dałem początek własnemu obiektowi przejściowemu QueryExecutionPlan, który ma mi być pomocny przy przekładaniu mojego Linq na dedykowana składnię SQL dla SQL Servera (T-SQL), Oracle'a (PL-SQL) czy też zestaw poleceń do wykonania dla własnej prostej bazy plikowej. Tutaj trochę zdradzam finał, który mam nadzieję niedługo opublikować czyli taki dostawca do Linq, który poprzez prostą konfigurację umożliwia komunikację z różnym fizycznym źródłem danych (poprzez wspólny metamodel).
Czyli krótko mówiąc idziemy powoli po bebechach w stronę EntityFramework (aloha Syzyfie, wymyślmy kolejne koło :>)

Jakby, ktoś chciał sobie przyspieszyć to jak wspomniałem przykłady alternatywne przykłady są dostępne w sieci. Na początku jednak polecam taką lekką drogę przez mekę aby zobaczyć co kryje się w pierwszym Expression jakie przekazujemy i jak dalej to wygląda gdy zagłebimy się w osadzone podwyrażenia.
To się może przydać przy optymalizacji generowanych zapytań jako odpowiedź dla co poniektórych, którzy ze składni LINQ są zadowoleni, ale może nie do końca z generowanych przez nie SQLi. UnitTesting przy takim projekcie moim zdaniem to jedno wielkie MUST-BE.

Podsumowując: jeśli założymy, że powyższe już mamy zrobione to jedyne co pozostaje to wykonać polecenie, odebrać wynik i zformatować go zgodnie z typem jaki zarządaliśmy w zapytaniu Linq. To już ponownie pozwolę sobie przesunąć na kolejną część.

 

[PL] Targi E3 - co na Xbox'a?

Nie wiem czy wiecie, ale za oceanem trwa teraz E3 2008 czyli Electronic Entertainment Expo 2008. To chyba największa konferencja w branży gdzie marketing dostawców platform (konsol) oraz wydawców gier puchnie w szwach od coraz to nowszych zapowiedzi, kontrolowanych przecieków i tak dalej. Dziś konferencja prasowa Microsoftu i od razu siejemy zamęt i zniszczenie, a na górze wisienka. :)

Wiele z intrygujących filmików znajdziecie na stronie www.gametrailers.com. Rozsądny komentarz na bieżąco też publikują koledzy z Polygamii. Jest nieźle. Z tego co sam na ten moment zdąrzyłem zobaczyć to:
* krótki filmik z gameplayem do Fallout 3, po którym jeszcze bardziej zapragnąłem tej gry.
* robiący wrażenie cooperative w Resident Evil 5 (po Xbox Live)
* Project Origin, który na mnie akurat wielkiego wrażenia nie zrobił, ale może dla twardych fanów F.E.A.R będzie to gratka.
* Więcej informacji na temat Lord of the Rings:Conquest, do którego sam jestem nastawiony z pewnym dystansem. Filozofia Starwars:Battlefront w świecie Tolkiena. Zabawa z mordowanie hobbitów grając siłami Saurona. No nie wiem.. Zawsze wolałem grać Aragorna i bronić bosostopych :)
* Do tego jeszcze nie dotarłem, ale Polygamia już rozkminiła, że Final Fantasy XIII będzie na Xbox'a! Ten nius dla coniektórych powinien być jednym z najbardziej wgniatających. To zbicie solidnego argumentu dla Sony. Zresztą poczytajcie komentarze na Polygamii. Wieje grobową atmosferą i zabójczym milczeniem od miłośników Sonyi.
* Fable 2 - gra wg Petera Molynuex już jest skończona. Zapowiada się ciekawie zwłaszcza gdy do rozgrywki zachęca sam Peter Molyneux. Jeden z magików sceny prezenterskiej w branży elektronicznej rozrywki.
* Lego:Batman - no po prostu chyba już mnie żadne Lego w wersji gry video nie zdziwi.
* Hydrophobia - tutaj nie mam pojęcia co to będzie, ale krótki filmik pokazuje, że twórcy gry odpowiadają na techniczne wyzwanie twórcom Bioshock jeżeli chodzi o efekty związane z wodą w grze (od caustic lighting po przez pixel/vertex shadery na powierzchni.. no kurcze trochę się tam dzieje przez te parę sekund). Pytanie tylko jak się w to będzie grało.
* XBox 360 będzie miał nowy dashboard (pełna historia na 1up.com http://www.1up.com/do/newsStory?cId=3168709). Oto zrzut ekranu:

image
Trochę mi to Wii przypomina na tyle na ile zapamiętałem z salonu znajomego. Zobaczymy :)

Cały czas się coś dzieje. Konferencja prasowa Microsoftu rozpoczęła się o 10:30AM PST czyli de facto 3h temu w stosunku do tego co teraz piszę.

Informacje na bieżąco na pewno znajdziecie tutaj: http://e3expo.com/.
Heheh.. no to dzisiaj chyba pospałem :>

[PL] Własny dostawca w LINQ (dla opornych) - cz. 2

Artykuł został rozbity na wiele części, poniżej spis treści:
I.  Budowa zapytania
II. Podstawy analizy drzewa wyrażeń
III. Właściwa analiza drzewa wyrażeń
IV. Pobieranie i zwrot danych

Podstawy analizy drzewa wyrażeń

Kontynuując zabawę w własnego dostawcę do Linq chciałem rozwinąć kwestię analizy drzewa wyrażeń i tłumaczenia go na konkretne polecenia (np. SQL). W poprzedniej części wspomniałem o jednej z metod interfejsu IQueryProvider, czyli o BasicQueryProvider.Execute oraz BasicQueryProvider.Execute<T> w naszej implementacji dostawcy.

Stworzony już prosty test rozbudujemy o próbę realnego wykonania zapytania, chociażby poprzez odwołanie do pierwszego znalezionego rekordu:


      Query<Customer> q = new Query<Customer>();

var result = (from c in q
      where c.Age > 10
     
select c).First();
Console