Obwohl async / await nun schon eine ganze Weile existieren, bin ich jetzt das erste mal an einen Punkt angekommen, wo ich mir nicht sicher bin, wie es am besten implementiert wird. Und zwar folgendes:
Ich habe durch ein Framework, ein override, welches einen Task als Rückgabetypen hat. Nun benötige ich keinerlei asynchrones Verhalten in dieser Methode, da ich mir den Parameter nur in ein Field speichern möchte.
Aber was gebe ich nun in der Methode zurück? Ein Task.Delay(0)? Sieht mir nicht sonderlich elegant aus. Was macht ihr in solchen Fällen? Leider konnte ich bei Google auch nicht wirklich eine Antwort dazu finden. Es gibt zwar ein paar Ansätze dort, aber so elegant sind diese alle nicht.
WAGO Kontakttechnik GmbH & Co. KG / Software Notion
Softwareentwicklung
C# .NET with WPF, ASP, Xamarin and Unity
Personal Blog: Development Blog
Nimm den Task und rufe Wait() auf.
Dann kannst du aud Task.Result das Ergebnis liefern.
Habe einen ähnlichen Fall in einem Projekt bei uns.
Dort bekomme ich nur Async Methode obwohl ich auf das Ergebnis warten muss.
Also nehme ich den Task entgegen, warte auf diesen und liefere dann aus dem Result des Tasks das eigentliche Ergebnis bzw. wandle dieses dann um.
@HiGHteK
Für mich wird aus der Doku nicht ganz ersichtlich, in wie weit CompletedTask hier der richtige Ansatz wäre.
Da dies eine static Instanz ist, kann man gar nicht wissen welcher Task dies ist.
Kann auch ein völlig andere Task sein, wie der Hinweis am Ende auch hindeutet:
Repeated attempts to retrieve this property value may not always return the same instance.
T-Virus
Developer, Developer, Developer, Developer....
99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.
@T-Virus
Der TE will eine Methode überschreiben (override).
Ich habe durch ein Framework, ein override, welches einen Task als Rückgabetypen hat. ...
Aber was gebe ich nun in der Methode zurück?
Also hat er eine Basis-Klasse die ungefähr so aussieht:
abstract class Foo
{
public abstract Task DoBarAsync( object parameter )
}
In der abgeleiteten Klasse ist aber nichts was wirklich asynchron erfolgt. Also hat er keinen Task, den er zurückgeben kann.
class ConcreteFoo : Foo
{
object _bar_parameter;
public override Task DoBarAsync( object parameter )
{
_bar_parameter = parameter;
return ... // what???
}
}
Hier ist ein Task.CompletedTask
genau das, was man dort zurückgeben möchte.
Diese statische Eigenschaft gibt es allerdings erst ab .NET 4.6. In einigen Libraries sieht man dort z.B. als Rückgabewert ein Task.FromResult( false )
was eben auch ein abgeschlossener Task ist.
Hier ist ein
Task.CompletedTask
genau das, was man dort zurückgeben möchte.Diese statische Eigenschaft gibt es allerdings erst ab .NET 4.6. In einigen Libraries sieht man dort z.B. als Rückgabewert ein
Task.FromResult( false )
was eben auch ein abgeschlossener Task ist.
Das Projekt ist leider ein .NET 4.5 Projekt und somit ohne CompletedTask. Den werde ich wohl bei einen Task bleiben müssen, der ohnehin direkt abgeschlossen ist. Also Task.Delay(0), Task.FromResult(XY) oder was auch immer.
WAGO Kontakttechnik GmbH & Co. KG / Software Notion
Softwareentwicklung
C# .NET with WPF, ASP, Xamarin and Unity
Personal Blog: Development Blog
Hallo T-Virus,
Nimm den Task und rufe Wait() auf.
Dann kannst du aud Task.Result das Ergebnis liefern. N E I N ! ! ! Das blockiert den Thread ist sicher nicht das gewünschte Verhalten.
Hallo Sebastian1989101,
Also Task.Delay(0), Task.FromResult(XY) oder was auch immer.
Ist beides nicht ideal, da immer ein Task-Objekt erstellt werden muss und dieses vom GC dann abgeräumt werden muss. Task.Delay ist dazu noch schlechter -- kannst du selber nachlesen.
Erzeuge besser einmalig pro AppDomain einen abgeschlossenen Task und cache diesen, damit dieser verwendet werden kann. Task.CompletedTask macht nichts anderes. Also:
private static Task _completedTask = Task.FromResult(42);
Aber die Lösung zur Frage, sofern ich sie richtig verstanden habe, lässt sich einfacher und eleganter umsetzen (anhand des Beispiels von Sir Rufo):
class ConcreteFoo : Foo
{
object _bar_parameter;
public override Task DoBarAsync( object parameter )
{
_bar_parameter = parameter;
return base.DoBarAsync(parameter);
}
}
😉
mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.
"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
Was für einen konkreten Task liefert das denn zurück, wenn die Methode in der Basis-Klasse abstract
deklariert ist?
Hallo Sir Rufo,
aahh, ich hab dein abstract
übersehen (weils in der Frage oben auch nicht steht), dann geht das natürlich nicht. Solle es aber eine nicht-abstrakte Basisklasse sein, so wäre dies der bevorzugte Weg.
Danke für den Hinweis!
mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.
"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
Ist leider abstract. 😉 Handelt sich um genau zu sein um die Initialize-Methode der MvvmCross ViewModel.
WAGO Kontakttechnik GmbH & Co. KG / Software Notion
Softwareentwicklung
C# .NET with WPF, ASP, Xamarin and Unity
Personal Blog: Development Blog
Hallo Sebastian1989101,
der Sinn hinter dem Ganzen kommt mir ein wenig komisch vor. Was hast du mit diesem Konstrukt vor?* eine Basisklasse für deine ViewModels
Je nachdem gibt es u.U. schönere Abbildungen davon. Z.B.* wenns die Basisklasse sein sollte: so können die Kindklassen diesen Parameter ja an base (deine Klasse) übergeben
Ich weiß aber nicht was es werden soll, daher hänge ich da noch in der Luft.
mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.
"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
Einfache Sache - eigentlich:
Zwei potentielle Varianten für die synchrone Umsetzung:
public Task Foo()
{
return Task.CompletedTask;
}
public Task<T> Foo()
{
T obj = irgendwoher synchron das T
return Task.FromResult(obj);
}
Für vor .NET 4.6
private static Task completedTask = Task.FromResult(false);
public static Task CompletedTask()
{
return completedTask;
}
Mehr oder weniger nichts anderes ist auch der originale Source dazu.
Hab aber auch schon das hier gesehen:
public static Task CompletedTask()
{
return new Task(() => { });
}
Bei FromResult würde man über ein TaskCompletionSource
gehen, sofern man auf .NET 4.0 (und nicht höher) angewiesen ist.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Hallo Abt,
soweit waren wir weiter oben schon 😉
Und es ist .net 4.5, da gibt es CompletedTask nicht.
mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.
"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
Lass mich zuende schreiben gfoidl 😛
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
der Sinn hinter dem Ganzen kommt mir ein wenig komisch vor. Was hast du mit diesem Konstrukt vor?
Er leitet eine Klasse von einer Basis-Klasse aus einem externen Framework ab und muss nun diese in der Basis-Klasse als abstrakt definierte Methode Initalize
implementieren?
Man könnte also sagen, der Sinn und Zweck ist es, dieses externe Framework zu verwenden.
Hallo Sir Rufo,
ach wirklich? Darauf bin ich nicht gekommen 🤔
Ich hab ja auch konkrete Punkte angeführt was es sein könnte (Logging, eigene Basisklasse, ...) und will hinterfragen was er vorhat, denn ich glaube dass es eine besser Lösung gibt. Aber wenns nur um die Verwendung des externen Frameworks geht, so reich das natürlich 😉
mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.
"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
Er will ganz einfach eine ViewModel-Klasse erstellen.
Initialize-Methode der MvvmCross ViewModel
Und konkret geht es um die Implementierung von IMvxViewModel bzw. die Ableitung von MvxViewModel (die Methode sieht allerdings auch nicht abstract
aus).
Die konkreten Punkte habe ich gelesen, allerdings weiß ich nicht, wie man die hier in einen sinnvollen Kontext sehen kann oder in irgendeiner Art hilfreich sein sollten.
Bin mir über die Verwendung von Init in MvvmCross nicht sicher; sieht für mich aber nach einer Bad Practise aus.
Init-Methoden werden oft aus dem Konstruktor aufgerufen und daher können diese - stand heute - nicht asynchron ausgeführt werden.
Init an für sich sollte also gar nicht async sein.
Damit muss man jetzt aber leben.
Die potentiellen Lösungsmöglichkeiten wurde doch aber nun genannt...?!
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Hallo,
hier wird dann Initialiaze von der Init-Methode aufgerufen und Initialize ist virtual => return base.Initialize(...)
ist dann die Wahl (siehe oben).
die hier in einen sinnvollen Kontext sehen kann oder in irgendeiner Art hilfreich sein sollten.
Daher wäre es interessant was der OT dazu meint, der wird wohl wissen was er damit vorhat. Wir können nur raten.
Wenns um Logging geht, so ist oft ein Dekorator passender als eine (Zwischen-) Ableitung. Wenns ein weitere eigene Basisklasse werden soll, so ist das Vorgehen OK. Aber ich weiß nicht was es werden soll, da es noch nirgends steht.
Aber Abt hat recht, die Lösungen stehen schon ganz oben und das hier ist eher abweichend vom eigentlichen Thema -- das können wir aber abteilen wenn wir wissen worum es geht und solange der OT keine Antwort schreibt, macht es wenig Sinn hier weiter zu raten.
mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.
"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
Darf ich den einen Task den Ich mit FromResult erzeuge denn mehrmals verwenden? Microsoft macht ja da intern was anderes, und setzt noch das er nicht Disposed werden darf!
Siehe: (TaskCreationOptions)InternalTaskOptions.DoNotDispose
cSharp Projekte : https://github.com/jogibear9988
Hallo jogibear9988,
ja den kannst du ruhig öfters verwenden, warum auch nicht? Ist ja letztlich nur ein Objekt und somit auch nicht anders zu behandeln als jedes andere Objekt in .net.
Wenn -- wie oben erwähnt -- der Task in einem statischen Feld gehalten wird, so räumt den der GC auch nicht weg, da die Referenz auf diesen eben so lange lebt wie die AppDomain, also i.d.R. bis zum Ende des Prozesses.
mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.
"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"