sobota, 9 marca 2013

Późne generowanie obiektu

Ostatnio bawiłem się leniwą (późną) inicjalizacją obiektu przez klasę Lazy. Troszkę zaskoczyła mnie jej działanie. Chciałbym powielić jeden obiekt, który ma losowe wartości.
    public class ElementClient
    {
        public string Name = Path
.GetRandomFileName()
.Replace(".", "");

        public Guid Guid = Guid.NewGuid();
        public override string ToString()
        {
            return string.Format("Guid:{0} Name:{1}", Guid, Name);
        }
    }
Mamy pomocniczą metodę wyświetlająca elementy w liście
      private static void Print<T>(IEnumerable<T> elements)
        {
            foreach (var elementClient in elements)
            {
                Console.WriteLine(elementClient);
            }
        }
Jeżeli powielę jeden obiekt to dostaje takie same wartości.
            int repeatNumber = 5;
            var elements = Enumerable.Repeat(new ElementClient(), repeatNumber);
            Print(elements);
Ale chciałbym stworzyć 5 obiekty, które mają różne wartości. Więc muszę wcześniej stworzyć klasę, która inicjalizuje obiekt wtedy gdy dany obiekt będzie potrzebny.
    public class Invoker<T>
    {
        public T Value
        {
            get { return _func(); }
        }
        private Func<T> _func;
        public Invoker(Func<T> func)
        {
            _func = func;
        }
    }
            var elements2 = Enumerable
                .Repeat(new Invoker(() => 
                                        new ElementClient()), repeatNumber)
                .Select(x => x.Value)
                .ToList();
            Print(elements2);

To samo chcemy zrobić za pomocą klasy Lazy<T>
     var elements3 = Enumerable
                .Repeat(new Lazy<ElementClient>(), repeatNumber)
                .Select(x => x.Value)
                .ToList();
            Print(elements3);
Ale dostałem takie same wartości. Uważaj na klasę Lazy<T> - nie zawsze działa tak jak myślisz.

środa, 6 marca 2013

Zmiana rozmiaru zdjęć za pomocą PowerShell

Czy masz może bardzo dużo zdjęć w jednym katalogu, musisz zmienić rozmiar tych zdjęć i za każdym razem uruchamiasz program graficzny, aby zmienić rozmiar zdjęcia??
Ja akurat tak miałem wiele razy :)
Jeśli coś powtarzasz wielokrotnie to postaraj się zautomatyzować tą czynność. Poniżej jest skrypt, który zmienia rozmiar zdjęcia.
function Resize-Image {
[CmdletBinding()]
Param(
     [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] 
     [System.io.FileInfo] $filepath,
     [int] $width=100,
     [int] $height=100,
     [string]$prefix="rs_"
)

PROCESS{
        $filePathFullName = $filepath.FullName
        if( Test-Path $filePathFullName)
        {
            $destName = $prefix+$filepath.name
            $destPath = Join-Path -path  $filepath.DirectoryName $destName
            
            import-bitmap $filePathFullName | resize-bitmap -Width $width -Height $height | export-bitmap  -Path $destPath 
            Write-Host "Resizing into $destPath"
                   
        }
        else {
            Write-Host "Path not found."
            }
        }
}
Przykład użycia jest przedstawiony poniżej:
gci -filter *.bmp |  Resize-Image 

Ten skrypt może u ciebie nie działać, bo prawdopodobnie nie masz PowerShell Community Extensions. Skrypt korzysta z poleceń import-bitmap,resize-bitmap i export-bitmap, które znajdują się w PSCX. Aby zainstalować PSCX, to wystarczy pobrać paczkę ze strony internetowej. Rozpakować do jednej z lokalizacji zawartej w zmiennej $Env:PSModulePath. A na końcu wywołać poniższy skrypt:
Import-Module Pscx -arg ~\PSCX\Pscx.UserPreferences.ps1
Get-Module

Mam nadzieję, że skrypt się przyda :)

wtorek, 5 marca 2013

Problemy z produktywnością


Znasz może ten żart:

Są rodzaje seksu: więzienny, studencki, przedszkolny i filozoficzny.
Więzienny: Jest gdzie, ale nie ma z kim,
Studencki: Jest z kim, ale nie ma gdzie.
Przedszkolny: Jest gdzie, jest z kim, ale nie ma czym.
Filozoficzny: Jest gdzie, jest z kim, ale czy jest sens...?



Wydaje mi się, że tak sam podział może być z problemami produktywności.

Przedszkolny: nie ma zadań, nie wiadomo jak, nie ma narzędzi.
Studencki: są zadania, nie ma wiedzy(jeszcze nie), są narzędzia.
Więzienny: są zadania, jest wiedza, nie ma narzędzi.
Filozoficzny: są zadania, jest wiedza, są narzędzia, ale jaki to ma sens?



Jeżeli jesteś typem przedszkolaka to nie musisz dbać o produktywność bo nie masz zadań. I z tego też powodu wszyscy ci zazdroszczą.

Jeżeli jesteś typem studenta to już powinieneś dbać o produktywność bo są zadania. Pomimo tego, że masz dostęp do narzędzi nie wykorzystujesz je. Mi bardzo brakuje dostępu do DreamSparka. Stamtąd można było pobrać bardzo dużą ilość programów za darmo. Doceniłem to dopiero po studiach.

Jeżeli jesteś typem więźnia to masz zadania i wiedzę, które mogą zwiększyć produktywność. Ale nie masz wymaganych narzędzi. Z taką sytuacją może się spotkać, gdy pracujesz w firmie, gdzie nie ma dostępu do potrzebnych narzędzi.

Jeżeli jesteś filozofem. to masz zadania do zrobienia, potrzebną wiedzę, wymagane narzędzia, ale nie obchodzi cię czy jesteś produktywny. Masz swoje przyzwyczajenia, które nie chcesz zmieniać.


niedziela, 3 marca 2013

Mój wzorzec pipeline

Pipeline to łańcuch połączonych kroków,które procesują informację. Każdy krok dostaje obiekt i wykonuje jakąś akcje na tym obiekcie zanim zostanie wysłany do następnego kroku. Pipeline łączy jednostki procesowania, które mogą być klasami, metodami lub komponentami. Object pipeline składa się z 3 grup: klientów, klasy bazowej oraz z klas przedstawiający dany kroku. Klient tworzy obiekt, który ma być procesowany i wie jaki jest pierwszy krok. Klasa bazowa jest abstrakcyjna, posiada metodą, która zarządza wywołaniem. Pobiera obiekt, przetwarza go a następnie przesyła do następnego kroku. Klasa bazowa posiada też obiekt typu klasy bazowej reprezentujący następny kroków, do której tylko klasy dziedziczące mają dostęp. Klasa z krokiem dziedziczy po klasie bazowej. Schemat jest przedstawiony poniżej:



Na samym początku stwórzmy pomocnicze metody:
public class HelpClass
    {
        public static IEnumerable<T> GenerateData<T>(Func<int, T> func)
        {
            for (int i = 0; ; i++)
            {
                yield return func(i);
            }
        }

        public static DescriptionAttribute GetClassDescriptionAttribute(Type type)
        {
            return type
.GetCustomAttributes(typeof(DescriptionAttribute), false)
.FirstOrDefault() as DescriptionAttribute;
        }
    }
Następnie stwórzmy abstrakcyjną klasę bazową, po której klasy z implementacją kroku będą dziedziczyć.Klasa ta będzie miała abstrakcyjną metodę - Handle(T input).
      public abstract class BaseStep<T>
    {
        protected BaseStep<T> _nextStep;
        public void SetNextStep(BaseStep<T> nextStep)
        {
            _nextStep = nextStep;
        }
        public T HandleProcess(T input)
        {
            var desc = HelpClass
.GetClassDescriptionAttribute(this.GetType());

            if(desc != null)
                Console.WriteLine(desc.Description);
 
            var items = Handle(input);
            return _nextStep != null ? _nextStep.HandleProcess(items) : items;
        }
 
        protected  abstract T Handle(T input);
    }
Teraz możemy napisać poszczególne implementacje kroków. Niech pierwszy krok będzie usuwał pierwszy element w liście, a drugi krok będzie usuwał duplikaty. Skorzystamy z atrybutu Description, aby mieć opis w którym kroku jesteśmy.
      [Description("Filters first element")]
    public class FilterFirstStep<T> : BaseStep<IEnumerable<T>>
    {
        protected override IEnumerable<T> Handle(IEnumerable<T> input)
        {
              return input.Skip(1);
        }
    }
 
    [Description("Filters duplicated elements")]
    public class FilterDuplicatedStep<T> : BaseStep<IEnumerable<T>>
    {
        protected override IEnumerable<T> Handle(IEnumerable<T> input)
        {
            return input.Distinct();
        }
    }
Dodatkowo stwórzmy krok, który będzie zawierał informacje jak długo trwało przetwarzanie listy.
    [Description("Measuring step")]
    public class MeasureStep<T> : BaseStep<IEnumerable<T>>
    {
        public long Elapsed { get; private set; }
        protected override IEnumerable<T> Handle(IEnumerable<T> input)
        {
            Stopwatch stopwatch = Stopwatch.StartNew();
            var result = input.ToList();
            Elapsed = stopwatch.ElapsedMilliseconds;
            return result;
        }
    }
Teraz jak mamy wszystkie kroki to możemy zająć się testowaniem pipelineu.
            Random random = new Random();
            var items = HelpClass.GenerateData(i => random.Next(i)).Take(90000);
            MeasureStep<int> measure = new MeasureStep<int>();
            FilterFirstStep<int> filterFirst= new FilterFirstStep<int>();

            measure.SetNextStep(filterFirst);
            filterFirst.SetNextStep(new FilterDuplicatedStep<int>());


            var hanled = measure
                .HandleProcess(items)
                .ToList();

            Console.WriteLine(measure.Elapsed);
I na konsoli mamy:
Wzorzec object pipeline ma jeden duży minus - dane wejściowe musza być tego samego typu co dane wyjściowe.


Dziedziczenie w c#

Co jakiś czas napotykam na problemy związane z Co- i Contra- wariancją, więc postanowiłem troszkę pobawić się z .NETem. Chciałbym przedstawić dlaczego jest z tym taki problem. Niech poniższy wpis będzie wstępem do większego zagadnienia.
Stwórzmy 2 klasy. Jedna (B) będzie dziedziczyła po drugiej (A)
class A
{
}
 
class B : A
{
}

Aby poprawić czytelność stwórzmy extension method, która będzie określała czy jeden typ dziedziczy od drugiego typu:
 public static class TypeExt
{
 public static bool IsFromType<T>(this Type type)
 {
     return typeof(T).IsAssignableFrom(type);
 }
}

Teraz możemy sprawdzić co zwróci nam ta metoda.
     Console.WriteLine(typeof(A).IsFromType<A>()); //true 
     Console.WriteLine(typeof(B).IsFromType<A>()); //true 
     Console.WriteLine(typeof(A).IsFromType<B>()); //false 

Sprawdzamy jak będzie dla typów generycznych.
 Console.WriteLine(typeof(List<B>).IsFromType<List<B>>()); //true
 Console.WriteLine(typeof(List<B>).IsFromType<IEnumerable<B>>()); //true

Typy generyczne są tak samo traktowane jak 'normalne' typy. Ale co będzie, kiedy argumenty w typach generycznych będą różne lub jeden argument będzie dziedziczony po drugim??
    Console.WriteLine(typeof(List<B>).IsFromType<List<A>>()); //false

Nawet jeżeli typ generyczny będzie taki sam, argumenty w typie generycznym będą inne, ale w relacji dziedziczenia to nie ma zależności. Wtedy musimy porównywać argumenty tych typów generycznych.
public static bool IsGenericArgFromType<T>(this Type type)
{
   var args1 = typeof(T).GetGenericArguments();
   var args2 = type.GetGenericArguments();

   return args1.Length == args2.Length &&
      args1.Zip(args2, (arg1, arg2) => new { arg1, arg2 })
      .All(x => x.arg1.IsAssignableFrom(x.arg2));
}

Console.WriteLine(typeof(List<B>).IsGenericArgFromType<List<A>>()); //true
Console.WriteLine(typeof(List<string>).IsGenericArgFromType<List<object>>()); //true
Pomimo tego, że argumenty w typie generycznym są w relacji dziedziczenia (przyporządkowania) to te dwa type nie są przyporządkowane do siebie. Taki sam problem jest, gdy mamy listę stringów i listę obiektów. W naturalny sposób lista stringów powinna być przyporządkowana do listy obiektów, ale tak nie jest.

SMART - nadużywany akronim

Mam wrażenie, że akronim SMART jest nadużywany. Wszyscy chcą teraz być smart - mądrzy, eleganccy, błyskotliwi, zwinni i sprytni. Więc słówko SMART bardzo łatwo staje się popularne, a zasada o tej samej nazwie ma coraz większą rzeszę zwolenników.



Ostatnio zaglądnąłem pod hasło SMART na Wikipedii, aby sprawdzić ile jest słówek rozwijających ten akronimem. Z tych wszystkich kombinacji można rozwinąć akronim na 13 824 sposobów. Jak jeszcze dołożymy literki ER to jest 580 608 sposobów. Przykład można zobaczyć w poniższym pliku. Wydaje mi się, że najważniejsze nie są literki, ale jaki przekaz niesie dana literka.



Już wcześniej pisałem o tym, że metoda SMART nie wystarcza w realizowaniu celów, ale uważam, że jest bardzo dobrą metodą przy wyznaczaniu celów.

sobota, 2 marca 2013

Zamykanie Windows 8

Musze się przyznać, że jak pierwszy raz uruchomiłem Windows 8 to nie wiedziałem, gdzie jest przycisk do zamykania komputera. Po pewnym czasie w końcu znalazłem. Jeżeli jesteś użytkownikiem Windows 8, to miałeś może taki problem jak ja??



W każdym razie nie o problemach szukania przycisku chciałbym napisać, ale o szybkim zamykaniu systemu.
Na samym początku stwórz skrót ma pulpicie.

Jako program wykonywalny wpisz:

shutdown.exe /s /t 00

Inne opcje są podane na tej stronie.

Polecam wybranie sobie ikonki.


Zaznacz sobie prawym przyciskiem myszy i wybierz "Przypnij do ekranu startowego" ("Pin to Start").



W menu Start przenieś przycisk tam gdzie chcesz. Oczywiście możesz dodać inne opcje zamykania (np. restartowanie).


Na końcu możesz jeszcze usunąć te skróty, które stworzyłeś na pulpicie - usunięcie ich nie wpływa na funkcjonalność okna Start.