Thomas Bandt

Über mich | Kontakt | Archiv

C# async/await: Tasks und out-Parameter - eine Alternative

Ich bin ein Freund davon, Code so explizit wie möglich zu schreiben. Geht es beispielsweise um ein Repository, das mir in einer Methode einen Kommentar zurück gibt, möchte ich nicht im aufrufenden Code anschließend auf null prüfen müssen, weil ich mir unsicher bin, ob wirklich ein Kommentar zurückkommt, oder nicht doch null.

Dort, wo ein Crash an der Stelle okay ist, weil der Kommentar ganz sicher da ist, würde die Methode schlicht Single() lauten, dort, wo das nicht der Fall ist, immer TrySingle().

Im .NET-Framework hat sich dafür ein nettes Pattern etabliert:

public bool TrySingle(int id, out Comment) {}

Aufruf:

Comment comment;
if (!_repository.TrySingle(id, out comment))
{
	// Behandle den Fehler
}

Nun stelle ich gerade ein solches Repository auf async/await um, womit ich mit dieser Vorgehensweise ein klitzekleines Problem habe, denn dieser dafür notwendige Code kompiliert nicht:

public Task<bool> TrySingle(int id, out Comment) {}

Tasks dürfen keine Out-Parameter besitzen. Ohne Task aber auch kein async/await.

Eine Möglichkeit wäre die Verwendung eines Tuples, allerdings habe ich persönlich die Erfahrung gemacht, dass die in C# sehr, sehr schnell sehr, sehr hässlich werden. Vor allem hässlich zu lesen.

Eine Alternative ist ein eigener Datentyp, der als Boolean fungiert, womit sich die Nutzung nicht großartig verändert:

public class Maybe<T> where T : class
{
	public T Value { get; set; }

	public static implicit operator bool(Maybe<T> t)
	{
	    return t.Value != null;
	}
}

Die Repository-Methode schaut nun aus wie folgt:

public Task<Maybe<Comment>> TrySingle(int id) {}

Und ihr Aufruf:

Maybe<Comment> comment = await _repository.TrySingle(id);
if (!comment)
{
	// Behandle den Fehler
}

Ich habe die Umstellung gerade erst begonnen, es fühlt sich jedoch sehr angenehm in der Verwendung an.



« Zurück  |  Weiter »