| 

.NET C# Java Javascript Exception

0
Gestern hatte ich eine Möglichkeit gezeigt, mit der man auf einfache Weise Komponenten asynchron machen kann und diese im Anschluss event based zu verwenden. Heute möchte ich das Beispiel erweitern und etwas näher in die Praxis rücken. Zunächst verwende ich keine Standardtypen mehr sondern definiere mir eine Datenklasse. public class Item { public Item() { […]

Gestern hatte ich eine Möglichkeit gezeigt, mit der man auf einfache Weise Komponenten asynchron machen kann und diese im Anschluss event based zu verwenden. Heute möchte ich das Beispiel erweitern und etwas näher in die Praxis rücken. Zunächst verwende ich keine Standardtypen mehr sondern definiere mir eine Datenklasse.

public class Item
{
 public Item()
 {
 Id = Guid.NewGuid().ToString();
 }

 public string Id
 {
 get;
 set;
 }

 public override string ToString()
 {
 return Id;
 }

 public static IEnumerable<Item> Get(int count)
 {
 List<Item> items = new List<Item>();
 for (int i = 0; i < count; i++)
 {
 items.Add(new Item());
 }
 return items;
 }
}

Ich möchte Instanzen dieser Klasse asynchron in einem Repository speichern und jeweils benachrichtigt werden, wenn ein Element gespeichert wurde. Das Repository ist hier einfach.

class RepositoryService
{
 public void SaveItem(Item item)
 {
 Console.WriteLine("Save : {0}", item);
 Thread.Sleep(50);
 }
}

Ich will auch wissen, welches Item gespeichert wurde. Ich kann eine Funktion definieren und den Rückgabewert entsprechend setzen. Jetzt verwende ich aber nur mal Actions. In ProcessAsync sorge ich dafür, dass der Parameter der Funktion Process in OnCompleted wieder verwendet wird. Außerdem wird der SynchrinzationContext für die problemlose Verwendung in einer UI verwendet.

public class ProcessAsync<P>
{
 private Action<P> action;
 private readonly SynchronizationContext ctx = SynchronizationContext.Current;

 public ProcessAsync(Action<P> action)
 {
 this.action = action;
 }

 public void Process(P parameter)
 {
 action.BeginInvoke(parameter, new AsyncCallback(WorkCallback), parameter);
 }

 public event Action<P> OnCompleted = (s) => {};

 private void WorkCallback(IAsyncResult result)
 {
 var action = (Action<P>)((AsyncResult)result).AsyncDelegate;
 var param = (P)((AsyncResult)result).AsyncState;
 action.EndInvoke(result);

 if (ctx != null)
 ctx.Send(x => OnCompleted(param), null);
 else
 OnCompleted(param);
 }
}

Dann leite ich von ProcessAsync ab und definiere mir damit die Funktionalität um in das Repository zu schreiben. Das geht jetzt sehr schnell. Alternativ kann ich ProcessAsync auch innerhalb einer Klasse instanzieren und verwenden.

class SaveItems : ProcessAsync<Item>
{
 public SaveItems(RepositoryService service) : base(
 (item) => service.SaveItem(item))
 {}
}

Und damit sind wir schon fast am Ende und gehen zur Hauptroutine. Hier wird die Funktion zum Speichern instanziiert und das gewünschte Repository übergeben. Wir verbinden OnCompleted mit der Ausgabe und arbeiten 10 generierte Items ab.

class Program
{
 static void Main(string[] args)
 {
 var p = new SaveItems(new RepositoryService());
 p.OnCompleted += (s) => Console.WriteLine("Saved : {0}", s);

 foreach (var item in Item.Get(10))
 {
 p.Process(new Item());
 }

 Console.ReadLine();
 }
}

Als Ergebnis erhalten wird die folgende Ausgabe und sehen recht gut die asynchrone Verarbeitung. Am besten gefällt mir bei dieser Lösung das die asynchrone Verarbeitung von der Logik getrennt werden kann, wie in SaveItems gezeigt. SaveItems definiert nur die Funktionalität in das injizierte Repository zu speichern. ProcessItems definiert nur die Funktionalität beliebige Actions asynchron auszuführen. Die Items sind was sie sein sollen, eben nur Daten.

image


event-based-components flow parallel async
Schreibe einen Kommentar:
Themen:
async parallel flow event-based-components
Entweder einloggen... ...oder ohne Wartezeit registrieren
Benutzername
Passwort
Passwort wiederholen
E-Mail