Pokazywanie postów oznaczonych etykietą invoke. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą invoke. Pokaż wszystkie posty

poniedziałek, 28 kwietnia 2014

[C#|Visual Studio] C#: Reflection

Reflection to potężne narzędzie, za pomocą którego można zrobić wiele dobrego jak również i wiele złego w każdej .NET-owej aplikacji. Najważniejsze klasy, to Type, Assembly, Activator oraz wszystkie opisujące składowe typów, czyli MethodInfo, PropertyInfo, ConstructorInfo, FieldInfo, EventInfo itd. Poza swobodnym przeglądaniem assemblies za pomocą kodu, reflection ma zastosowanie w operacjach wykonywanych dynamicznie na starcie aplikacji. W każdym innym wypadku musimy liczyć się ze sporym spadkiem wydajności w stosunku do kodu statycznie typowanego.

Klasa assembly pozwala na odczytywanie metadanych z różnych assemblies a także ładowanie ich.

var current = Assembly.GetExecutingAssembly();

Console.WriteLine("Current assembly: " + current.FullName);

var fromGac =
    Assembly.Load("System.Xml.Linq,Version=4.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089");

var restSharpAssembly = Assembly.LoadFrom("RestSharp.dll");

Console.WriteLine("\nLoaded assembly: " + restSharpAssembly.FullName);
var dependant = restSharpAssembly.GetReferencedAssemblies();

Console.WriteLine("\nReferenced assemblies:");
foreach (var assemblyName in dependant)
    Console.WriteLine("\t" + assemblyName.FullName);

Metoda GetExecutingAssembly zwróci nam informacje o assembly, w którym ją wywołujemy (np. plik exe). Za pomocą metody Load możemy ładować assemblies z Global Assembly Cache, podając full name. Z kolei dla assemblies bez strong name możemy użyć metody LoadFrom lub LoadFile szukających na dysku. Jeżeli interesują nas zależne assemblies, możemy uzyskać do nich dostęp przy użyciu metody GetReferencedAssemblies.

Mając obiekt typu Assembly możemy pobrać wszystkie publiczne typy w nim zdefiniowane - służy do tego metoda GetExportedTypes..

Console.WriteLine("\nPublic types:");
            var types = restSharpAssembly.GetExportedTypes();

            foreach (Type type in types)
                Console.WriteLine("\t" + type);

            var stype = (from type in types
                        orderby type.GetCustomAttributes(true).Count() descending
                        select type).First();

            var instance = Activator.CreateInstance(stype);
            Console.WriteLine("\nCreated type instance:" + stype.FullName);

            var props = stype.GetProperties();
            Console.WriteLine("Properties:");
            foreach (var propertyInfo in props)
                Console.WriteLine("\t" + propertyInfo.Name);

            var tfields = (from type in types
                           let fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic)
                           orderby fields.Count() descending
                           select fields).First();

            foreach (var fieldInfo in tfields)
                Console.WriteLine("\t" + fieldInfo.Name);

Na każdym z typów możemy sprawdzić, jakie zdefiniowano atrybuty (GetCustomAttributes), a także pobrać wszystkie properties (GetProperties) czy pola (GetFields), także te prywatne, ustawiając odpowiednie flagi. Klasa Activator pozwala nam na tworzenie instancji dowolnego typu (rzutowanej do object). Mając taką instancję możemy pobrać MethodInfo i wywołać taką metodę przekazując do niej parametry.

var sw = new Stopwatch();
sw.Start();
var jsonArray = new JsonArray();
for (int i = 0; i < 1000000; i++)
{
    jsonArray.Add(i);
}
Console.WriteLine("Invoking instance method: {0} ms", sw.ElapsedMilliseconds);
sw.Restart();

var methodInfo = stype.GetMethod("Add");
for (int i = 0; i < 1000000; i++)
{
    methodInfo.Invoke(instance, new object[] {i});
}
Console.WriteLine("Invoking method via reflection: {0} ms", sw.ElapsedMilliseconds);
sw.Reset();

Porównanie takie wypada zdecydowanie na niekorzyść Reflection, głównie przez iterowanie po metadanych i boxing parametrów wejściowych.

Invoking instance method: 83 ms
Invoking method via reflection: 2241 ms

poniedziałek, 18 lutego 2013

[C#|Visual Studio] Threading: klasa Parallel

Kolejną ciekawą funkcjonalnością wprowadzoną w .NET 4.0 jest klasa Parallel. Udostępnia ona trzy metody umożliwiające zrównoleglenie wykonywania kodu.
  • Invoke - wykonuje równolegle tablicę delegatów
  • For - pętla for wykonywana równolegle
  • Foreach - pętla foreach wykonywana równolegle
Metody te zapewniają wysoką wydajność przy zrównoleglaniu obliczeń, ponieważ wykorzystują mechanizm Tasków, zatem np. gdy podamy sto delegatów, to zostaną one rozpartycjonowane na taką ilość tasków, by zapewnić maksymalną efektywność.Wykonywania każdej z tej funkcji zakończy się, gdy skończą działanie wszystkie taski.

static void InvokeTest()
{
    Parallel.Invoke(() => new WebClient().DownloadString("http://www.agh.edu.pl/"),
        () => new WebClient().DownloadString("http://www.eaiib.agh.edu.pl/"));
}

static void ForTest()
{
    var keyPairs = new string[6];
    Parallel.For(0, keyPairs.Length,
                  i => keyPairs[i] = RSA.Create().ToXmlString(true));
    foreach (var keyPair in keyPairs)
        Console.Write(keyPair);
}

static void ForeachTest()
{
    var arr = new int[]
                  {
                      166, 147, 159, 156
                  };
    Parallel.ForEach(arr, 
        s => Console.WriteLine("Alfa Romeo {0}", s));
}

Metoda For jest przeładowana na wiele sposobów. Jeżeli potrzebujemy, by wykonywać skomplikowane operacje matematyczne, możemy skorzystać z wersji metody, w której możemy wykorzystać lokalną zmienną, inicjalizowaną przez jednego z delegatów.

static void ForLockerTest()
{
    object locker = new object();
    double grandTotal = 0;

    Parallel.For(1, 10000000,
      () => 0.0,
      (i, state, localTotal) =>
         localTotal + Math.Sqrt(i),
      localTotal =>
      { lock (locker) grandTotal += localTotal; }
    );

    Console.WriteLine(grandTotal);
}

niedziela, 2 września 2012

[WPF] Dispatcher : opóźnione wykonanie metody

W przypadku, gdy chcemy, aby dispatcher odczekał określony przez nas czas, a następnie wykonał określoną metodę, możemy skorzystać z klasy ThreadPool.

Poniższa ExtensionMethod rozwiązuje problem opóźnionego wywołania dispatchera.


internal static class Extensions
{
    public static void DelayedInvoke(this Dispatcher dispatcher, int delayMs, Action action)
    {
        ThreadPool.QueueUserWorkItem((o) =>
                                            {
                                                Thread.Sleep(delayMs);
                                                dispatcher.Invoke(action);
                                            });
    }
}