C# 6.0–bezparametrowe konstruktory oraz inicjalizacja automatycznych właściwości w konstruktorze

W nowej wersji c# zdecydowano się zezwolić na konstruktory bezparametrowe w strukturach danych. Kiedyś pisałem dlaczego, nie można było ich definiować w poprzednich wersjach języka. Chodziło po prostu o wydajność, szczególnie podczas alokacji tablic danych. Dodam, że w CLR zawsze było dozwolone posiadanie konstruktorów bezparametrowych i wyłącznie c# na to nie zezwalał.

W C# 6.0 możliwe już jest napisanie własnego konstruktora bez parametrów, ale wciąż należy pamiętać o możliwych problemach wydajnościowych. Zobaczmy na dwie analogiczne struktury:

public struct SampleStructWithDefaultCtor
{
   public SampleStructWithDefaultCtor()
   {
   }

   private int _x=0, _y=0;
}

public struct SampleStructWithoutDefaultCtor
{
   private int _x, _y;
}

Jedna z nich pomimo, że jest dozwolona w C# 6.0, wciąż będzie dużo wolniejsza. Zróbmy test:

class Program
{
   static void Main(string[] args)
   {
       const int n = 5000000;

       Stopwatch stopwatch = Stopwatch.StartNew();
       var sampleStructWithDefaultCtor = new SampleStructWithDefaultCtor[n];
       Console.WriteLine(stopwatch.ElapsedTicks);

       stopwatch = Stopwatch.StartNew();
       var sampleStructWithoutDefaultCtor = new SampleStructWithoutDefaultCtor[n];
       Console.WriteLine(stopwatch.ElapsedTicks);
   }     
}

Wynik:

image

Oczywiście różnica jest znacząca jednak w wielu przypadku jest to zwyczajnie mikro-optymalizacja.  Myślę, że po prostu zdecydowano się to ponieważ strata w wydajności nie ma aż tak wielkiego znaczenia, a konstrukcja jest czasami prosta. Z drugiej jednak strony, korzystamy ze struktur kiedy operujemy na bardzo dużej ilości danych i wtedy już taka różnica w wydajności może mieć znaczenie. Po prostu trzeba być świadomym implementacji wewnętrznej struktur i podejmować decyzję o architekturze w zależności od konkretnego przypadku.

Druga drobna rzecz o której mi umknęło, gdy pisałem o udogodnieniach w automatycznych właściwościach to ich inicjalizacja w konstruktorach. Wspomniałem, że istnieje możliwość deklaracji czystych getterów ponieważ wprowadzono inicjalizacje inline:

class Person
{
  public string FirstName { get; } ="Piotr";
  public string LastName { get; } = "Zielinski";
}  

Możliwe jest również inicjalizowanie tych wartości w konstruktorze:

class Person
{
   public Person()
   {
       FirstName = "Piotr";
       LastName = "Zielinski";
   }

   public string FirstName { get; }
   public string LastName { get; } 
}

Niestety w aktualnym CTP nie będziemy w stanie tego przetestować, ale najprawdopodobniej pojawi się to w oficjalnym wydaniu.

Leave a Reply

Your email address will not be published.