c# 7.0: Parametry wyjściowe

Od dawna (chyba od początku) w C# do dyspozycji mieliśmy słowo kluczowe out, służące do przekazywania parametrów na wyjście. Standardem stało się pisanie metod typu TryParse, które zwracają bool oraz wartość za pomocą parametru out, np.:

         int number;
         bool result = Int32.TryParse(text, out number);
         if (result)
         {
            Console.WriteLine("Converted '{0}' to {1}.", text, number);         
         }
         else
         {
           // error
         }

Składnia bardzo niewygodna. Trzeba było osobno deklarować zmienną przekazywaną jako out. Ponadto, funkcje takie często akceptowały kilka parametrów out. W takich sytuacjach, musieliśmy deklarować puste “kontenery” ponieważ nie było możliwości przekazania NULL albo jakieś innej wartości. W skrajny sytuacjach wyglądało to tak:

int value;
// unnecessary variables
int container1,container2, container3;
DoSomething(out value, out container1, out container2, out container3);

// do something with value

W C# 7.0 nie musimy osobno deklarować takich zmiennych i powyższy kod można przepisać do:

            if (Int32.TryParse("4343", out int number))
            {
                Console.WriteLine(number);
            }
            else
            {
                // error
            }

Jak widzimy, deklaracja odbywa się w wewnątrz wywołania. Po kompilacji uzyskamy klasyczny kod:

    private static void Main(/*Parameter with token 08000001*/string[] args)
    {
      int result;
      if (!int.TryParse("4343", out result))
        return;
      Console.WriteLine(result);
    }

Ze względu, że sygnatura jest z góry znana, można skorzystać ze słowa “var” zamiast deklarować jawnie typ integer:

               
            if (Int32.TryParse("4343", out var number))
            {
                Console.WriteLine(number);
            }
            else
            {
                // error
            }

Możliwe, że będzie można korzystać z wildcards czyli (nie zostało to jeszcze zatwierdzone do finalnej wersji 7.0):

        static void Main(string[] args)
        {            
            if (Int32.TryParse("4343", out *))
            {
                Console.WriteLine("OK");
            }
            else
            {
                // error
            }
        }

Byłoby to bardzo przydatne w sytuacjach, gdzie zainteresowani jesteśmy tylko jedną wartością, a sygnatura wymaga od nas podania np. 5 innych zmiennych. Niestety na dzień dzisiejszy nie jest to zaimplementowane w najnowszej wersji VS (Visual Studio 15′ Preview 4).

EventWaiter – testowanie zdarzeń

Dzisiaj chciałbym zaprezentować klasę EventWaiter. Znalazłem ją w repozytorium Roslyn na GitHub i w niektórych testach okazała się przydatna. Załóżmy, że mamy klasę eksponującą jakieś zdarzenie:

    class Sut
    {
        public event EventHandler Click;

        public void RaiseClickEvent()
        {
            Click?.Invoke(this,EventArgs.Empty);
        }
    }

Test zdarzenia mógłby wyglądać następująco:

        [Test]
        [Timeout(2000)]
        public void Test1()
        {
            // arrange
            var manualResetEvent = new ManualResetEvent(false);
            var sut = new Sut();

            sut.Click += (s, e) => { manualResetEvent.Set(); };

            // act
            sut.RaiseClickEvent();

            // assert
            manualResetEvent.WaitOne();
            Assert.Pass();
        }

Źródło klasy EventWaiter można znaleźć np. tutaj:
https://github.com/dotnet/roslyn/blob/master/src/Test/Utilities/Shared/FX/EventWaiter.cs

Kod:

  public sealed class EventWaiter : IDisposable
    {
        private readonly ManualResetEvent _eventSignal = new ManualResetEvent(false);
        private Exception _capturedException;

        ///
<summary>
        /// Returns the lambda given with method calls to this class inserted of the form:
        /// 
        /// try
        ///     execute given lambda.
        ///     
        /// catch
        ///     capture exception.
        ///     
        /// finally
        ///     signal async operation has completed.
        /// </summary>

        /// <typeparam name="T">Type of delegate to return.</typeparam>
        /// <param name="input">lambda or delegate expression.</param>
        /// <returns>The lambda given with method calls to this class inserted.</returns>
        public EventHandler<T> Wrap<T>(EventHandler<T> input)
        {
            return (sender, args) =>
            {
                try
                {
                    input(sender, args);
                }
                catch (Exception ex)
                {
                    _capturedException = ex;
                }
                finally
                {
                    _eventSignal.Set();
                }
            };
        }

        ///
<summary>
        /// Use this method to block the test until the operation enclosed in the Wrap method completes
        /// </summary>

        /// <param name="timeout"></param>
        /// <returns></returns>
        public bool WaitForEventToFire(TimeSpan timeout)
        {
            var result = _eventSignal.WaitOne(timeout);
            _eventSignal.Reset();
            return result;
        }

        ///
<summary>
        /// Use this method to block the test until the operation enclosed in the Wrap method completes
        /// </summary>

        /// <param name="timeout"></param>
        /// <returns></returns>
        public void WaitForEventToFire()
        {
            _eventSignal.WaitOne();
            _eventSignal.Reset();
            return;
        }

        ///
<summary>
        /// IDisposable Implementation.  Note that this is where we throw our captured exceptions.
        /// </summary>

        public void Dispose()
        {
            _eventSignal.Dispose();
            if (_capturedException != null)
            {
                throw _capturedException;
            }
        }
    }

Dzięki temu wrapperowi, nasz kod może wyglądać teraz tak:


        [Test]
        [Timeout(2000)]
        public void Test1a()
        {
            // arrange
            var waiter=new EventWaiter();            
            var sut = new Sut();
            sut.Click += waiter.Wrap<EventArgs>((sender, args) => { Assert.Pass()});

            // act
            sut.RaiseClickEvent();

            // assert
            waiter.WaitForEventToFire();
        }

Powyższy przykład jest prosty. W praktyce musimy wciąć pod uwagę różne scenariusze – np. gdy wyjątek jest wyrzucany albo musimy sprawdzić konkretne parametry zdarzenia. W takich sytuacjach, powyższy wrapper jest przydatny.

NUnit 3 – testy wykonywane równolegle

Wersja nUnit 3.0 wspiera wykonywanie testów równolegle.  Jeśli mamy testy integracyjne albo akceptacyjne, wtedy wykonywanie ich równolegle, w znaczący sposób może przyśpieszyć  CI. W przypadku testów jednostkowych nie ma już to takiego znaczenia, bo i tak powinny one wykonywać się szybko.

Zaczynamy oczywiście od instalacji pakietu nuget NUnit 3. Załóżmy, że mamy następujące, czasochłonne do wykonania testy:

   [TestFixture]
    public class Tests1
    {
        [Test]
        public void Test1()
        {
            Console.WriteLine("Test 1 - start");
            Thread.Sleep(1000);
            Console.WriteLine("Test 1 - end");
        }
    }

    [TestFixture]
    public class Tests2
    {
        [Test]
        public void Test2()
        {
            Console.WriteLine("Test 2 - start");
            Thread.Sleep(1000);
            Console.WriteLine("Test 2 - end");
        }
    }

    [TestFixture]
    public class Tests3
    {
        [Test]
        public void Test3()
        {
            Console.WriteLine("Test 3 - start");
            Thread.Sleep(1000);
            Console.WriteLine("Test 3 - end");
        }
    }

    [TestFixture]
    public class Tests4
    {
        [Test]
        public void Test4()
        {
            Console.WriteLine("Test 4 - start");
            Thread.Sleep(1000);
            Console.WriteLine("Test 4 - end");
        }
    }

Jeśli wykonamy je teraz, zostaną one odpalone w sposób sekwencyjny:

2

Czas wykonania to około 5 sekund, ponieważ domyślnie nie są one uruchamiane równoległe.
W Assembly.cs możemy umieścić globalny atrybut, który umożliwi ich zrównoleglenie, tzn.:

[assembly: Parallelizable(ParallelScope.Fixtures)]

Wynik:

1

Widzimy, że czas ich wykonania zmalał do 2 sekund.

Jeśli jakiś test chcemy wyłączyć z zrównoleglenia, wtedy wystarczy umieścić następujący atrybut:

[Parallelizable(ParallelScope.None)]

Jak widać, atrybut możemy stosować zarówno globalnie jak i selektywnie na konkretnych testach. Dobrze napisane testy nie powinny zależeć od kolejności ich wykonywania, zatem umieszczenie atrybutu Parallelizable globalnie jest rozsądnym podejściem.
Domyślna liczba wątków służąca do odpalenia testów zależy od procesora, a konkretnie liczby rdzeni. Możliwie jest jednak ręczne sterowanie liczbą wątków za pomocą następującego atrybutu:

[assembly:LevelOfParallelism(5)]

Warto również wspomnieć, że na dzień dzisiejszy nie istnieje możliwość wykonania konkretnych testów (metod) równolegle. Innymi słowy, możliwe jest zrównoleglenie wyłącznie klas (TestFixture).

Fuslogvw a assembly binding

Czasami proste debugowanie za pomocą Visual Studio nie wystarcza. Sposób w jaki biblioteki są ładowane zależy od wielu czynników i plików konfiguracyjnych. Jeśli np. nasza aplikacja wyrzuca wyjątek “MissingMethodException”, a w czasie debugowania wszystko działa jak należy, wtedy możliwe, że mamy problemy związane z assembly binding.

Narzędzie Fuslogvw wchodzi w skład Visual Studio i pozwala prześledzić jakie kolejno biblioteki ładowane są. Dzięki temu poznamy ich lokalizacje oraz wersje.

W celu uruchomienia fuslogvw, odpalamy najpierw wiersz poleceń Developer Command Propmpt (koniecznie jako administrator):
1Następnie wpisujemy “Fuslogvw.exe”, co spowoduje uruchomienie narzędzia:
2

W “Settings” możemy ustawić czy chcemy wyłącznie logować błędy czy wszystkie wiązania:
3

Następnie stwórzmy jakaś aplikację (np. ConsoleApp) w celu zobaczenia co zaloguje Fuslogvw. Po odpaleniu przykładowej aplikacji naciskamy “Refresh” w Fuslogvw:
4

Na ekranie zobaczymy kilka nowych wpisów. Klikając na jedno z nich przejdziemy do szczegółów:
5

W szczegółach widzimy wyraźnie jaka biblioteka jest ładowana i skąd. Z kolei jeśli jakieś biblioteki nie można załadować, wtedy logi będą wyglądać następująco:
6

Na screenshocie można zauważyć, które  ścieżki są kolejno brane pod uwagę, gdy pliku dll nie ma w głównym katalogu aplikacji.

LESS: rozszerzenia

Dzisiaj kolejne udogodnienie w CSS dostarczane przez LESS. W klasycznym CSS nie ma możliwości dziedziczenia klas. Jeśli chcemy, aby klasa B miała właściwości klasy A oraz kilka rozszerzających wtedy zwykle musimy duplikować kod.
W LESS rozszerzenia definiuje się następująco:

.childClass {
  &:extend(.baseClass);
  background: blue;
}

.baseClass {
  color: red;
}

Na wyjściu mamy:

.childClass {
  background: blue;
}
.baseClass,
.childClass {
  color: red;
}

Inna składnia to:

.childClass {
  background: blue;
}

.baseClass {
  color: red;
}

.childClass:extend(.baseClass){}

Więcej informacji znajduje się w dokumentacji. Na blogu zwykle planuję tylko umieszczać kilka przykładów jako wprowadzenie.

LESS: Mixins

Dzisiaj kolejna przydatna konstrukcja LESS. Często zachodzi potrzeba stworzenia klasy na podstawie kilku innych klas. Załóżmy, że mamy:

.class1
{
  color:red;
}
.class2
{
  font-size:10px;
}
.finalClass
{
  color:red;
  font-size:10px;
  
  border-color:blue;
}

FinalClass składa się zarówno z class1 jak i class2. Ponadto rozszerza możliwości o border-color. Za pomocą mixin możemy kod skrócić do:

.class1
{
  color:red;
}
.class2
{
  font-size:10px;
}
.finalClass
{
  .class1();
  .class2();
  
  border-color:blue;
}

Oczywiście w praktyce przydatne jest to, gdy klasy mają więcej właściwości niż jedna. W przypadku jednej właściwości lepiej skorzystać ze zmiennych.

Powyższy mixin wykona się do wspomnianych wcześniej stylów:

.class1 {
  color: red;
}
.class2 {
  font-size: 10px;
}
.finalClass {
  color: red;
  font-size: 10px;
  border-color: blue;
}

Możliwe jest również zadeklarowanie mixin za pomocą nawiasów ():

.class1()
{
  color:red;
}
.class2()
{
  font-size:10px;
}
.finalClass
{
  .class1();
  .class2();
  
  border-color:blue;
}

Różnica polega na tym, że na wyjściu nie pojawią się .class1\.class2:

.finalClass {
  color: red;
  font-size: 10px;
  border-color: blue;
}

Do mixin można przekazać parametry:

.class1(@color)
{
  color:@color;
}

.finalClass
{
  .class1(blue);
    
  border-color:blue;
}

Analogicznie, parametry mogą przyjmować domyślne wartości:

.class1(@color:green)
{
  color:@color;
}

.finalClass
{
  .class1();
    
  border-color:blue;
}

Należy pamiętać, że jeśli chce się przekazać kilka parametrów należy je oddzielić średnikiem tzn. @color;@color2 itd.

Tak jak w C#, parametry można przekazywać za pomocą nazwy czyli zamiast .class(red) można .class(@color:red). Do dyspozycji mamy również specjalny parametr o nazwie @arguments, który po prostu zawiera listę wszystkich argumentów:

.class1(@width;@style;@color)
{
  border:@arguments;
}

.finalClass
{
  .class1(@width:2px;@style:solid;@color:red);
    
  border-color:blue;
}

Czasami zachodzi potrzeba odpalenia różnych mixin w zależności od kontekstu, np. używanego urządzenia. Spójrzmy na następujący kod:

.class1(mobile)
{
  font-size:1px;
}
.class1(desktop)
{
  font-size:2px;
}


.finalClass
{
  .class1(mobile);
    
  border-color:blue;
}

Zdefiniowaliśmy tutaj różne mixin w zależności od typu urządzenia. Przekazując jako parametr mobile, ustawimy rozmiar czcionki na 1. Na wyjściu pojawi się zatem:

.finalClass {
  font-size: 20px;
  font-size: 1px;
  border-color: blue;
}

Jeśli zadeklarujemy pierwszy parametr jako zmienną wtedy uzyskamy generyczną klasę:

.class1(@device)
{
  border-width:4px;
}

.class1(mobile)
{
  font-size:1px;
}
.class1(desktop)
{
  font-size:2px;
}

.finalClass
{
  .class1(mobile);
    
  border-color:blue;
}

W powyższym przypadku “mobile” zostanie dopasowany do dwóch klas:

.finalClass {
  border-width: 4px;
  font-size: 1px;
  border-color: blue;
}

Jak widzimy, mixins mogą w znaczącym stopniu skrócić arkusze CSS poprzez unikanie duplikacji kodu.

LESS css – wprowadzenie, zmienne

Na blogu rzadko poruszam tematy CSS, ale czasami nawet jak ma się bardzo małą warstwę prezentacji, warto zainwestować trochę czasu w poznanie nowych bibliotek.

Dzisiaj chciałbym przedstawić LessCss.  Biblioteka stanowi pewnego rodzaju pre-processor, który rozszerza możliwości klasycznego CSS. Na wyjściu zatem pojawi się zwykły CSS, który jest obsługiwany przez wszystkie przeglądarki. Sprawą “kompilacji”, zajmiemy się w innym wpisie, ponieważ istnieje wiele sposobów. Jednym z nich jest np. kompilowanie za pomocą  JavaScript po stronie klienta. W tym poście będę korzystał z narzędzia online, które można znaleźć tutaj.

Załóżmy, że mamy kilka klas, które korzystają z tego samego koloru:


.customClass1
{
  color:red;
}

.customClass2
{
  color:red;
}

.customClass3
{
  color:red;
}

Za pomocą LESS możemy zdefiniować zmienną:

@customColor: red;

.customClass1
{
  color:@customColor;
}

.customClass2
{
  color:@customColor;
}

.customClass3
{
  color:@customColor;
}

Po w klejeniu wspomniany wcześniej edytor online, zobaczymy, że na wyjściu @customColor zostanie zastąpiona wartością Red. Wszelkie zmienne w Less definiujemy za pomocą @. Zmiana wartości odbywa się za pomocą znaku ‘:’ (dwukropek).

Wszelkie stałe zatem można w łatwy sposób umieścić tylko w jednym miejscu. Zmienne nie ograniczają się jedynie do wartości. Możliwe jest również umieszczenie selektorów CSS w nich, tzn.:

@customSelector: .customClass;

@{customSelector}
{
  color:red;
}

Po kompilacji:

.customClass {
  color: red;
}

Zmienna ładowane są w sposób “lazy-loading. W praktyce oznacza to, że nie muszą być deklarowane przed ich użyciem. Poniższy kod również wygeneruje taką samą odpowiedź:

@{customSelector}
{
  color:red;
}

@customSelector: .customClass;

Osobiście uważam, że może z tego wyniknąć wiele problemów.

W dokumentacji znalazłem również informacje, że możliwe jest korzystanie ze zmiennej jako nazwy dla kolejnej zmiennej. Spójrzmy na następujący kod:

@varName: 'test';
@test: 'red';

.customClass
{
  color:@@varName
}

Po kompilacji:

.customClass {
  color: 'red';
}

Moim zdaniem bardzo niebezpieczna konstrukcja. Podwójny operator @ wyciągnie najpierw wartość ze zmiennej varName, a potem użyje jej jako docelowej zmiennej.

W następnych wpisach skupie się na pozostałych możliwościach LESS oraz na kompilacji LESS do normalnego CSS.