Ich habe eine generische Methode, die eine Anfrage entgegennimmt und eine Antwort liefert.
public Tres DoSomething<Tres, Treq>(Tres response, Treq request)
{/*stuff*/}
Ich möchte jedoch nicht immer eine Antwort auf meine Anfrage, und ich möchte nicht immer Anforderungsdaten eingeben, um eine Antwort zu erhalten. Ich möchte auch nicht, dass Methoden vollständig kopiert und eingefügt werden müssen, um geringfügige Änderungen vorzunehmen. Was ich will, ist, dies tun zu können:
public Tre DoSomething<Tres>(Tres response)
{
return DoSomething<Tres, void>(response, null);
}
Ist das irgendwie machbar? Es scheint, dass die spezifische Verwendung von void nicht funktioniert, aber ich hoffe, etwas Analoges zu finden.
DoSomething(x);
statty = DoSomething(x);
Antworten:
Sie können nicht verwenden
void
, aber Sie können verwendenobject
: Es ist ein wenig unpraktisch, weil Ihre potenziellenvoid
Funktionen zurückgegeben werden müssennull
, aber wenn es Ihren Code vereinheitlicht, sollte es ein kleiner Preis sein, den Sie zahlen müssen.Diese Unfähigkeit,
void
als Rückgabetyp zu verwenden, ist zumindest teilweise für eine Aufteilung zwischen denFunc<...>
und denAction<...>
Familien der generischen Delegierten verantwortlich: Wäre eine Rückgabe möglich gewesenvoid
,Action<X,Y,Z>
würde alles einfach werdenFunc<X,Y,Z,void>
. Das geht leider nicht.quelle
void
von diesen Methoden zurückkehren, mit denen er nichtig wärereturn System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(void));
. Es wird jedoch eine Leere sein.void
in FP dargestellt wird. Und es gibt gute Gründe, es zu benutzen. In F #, immer noch .NET, haben wirunit
eingebaut.Nein, leider nicht. Wenn
void
ein "echter" Typ wäre (wie zum Beispielunit
in F # ), wäre das Leben in vielerlei Hinsicht viel einfacher. Insbesondere würden wir nicht sowohl dieFunc<T>
als auch dieAction<T>
Familien brauchen - es würde nurFunc<void>
stattAction
,Func<T, void>
stattAction<T>
usw. geben.Es würde auch die Asynchronisation einfacher machen - der nicht generische
Task
Typ wäre überhaupt nicht erforderlich - wir hätten es einfach getanTask<void>
.Leider funktionieren die Systeme vom Typ C # oder .NET nicht so ...
quelle
Unfortunately, that's not the way the C# or .NET type systems work...
Sie haben mich hoffnungsvoll gemacht, dass die Dinge vielleicht irgendwann so funktionieren könnten. Bedeutet Ihr letzter Punkt, dass wir wahrscheinlich nie so arbeiten werden?Hier ist was Sie tun können. Wie @JohnSkeet sagte, gibt es in C # keinen Einheitentyp, also machen Sie es selbst!
Jetzt können Sie immer
Func<..., ThankYou>
anstelle von verwendenAction<...>
Oder verwenden Sie etwas, das bereits vom Rx-Team erstellt wurde: http://msdn.microsoft.com/en-us/library/system.reactive.unit%28v=VS.103%29.aspx
quelle
Install-Package System.Reactive.Core
Kthx.Bye;
Sie können einfach verwenden,
Object
wie andere vorgeschlagen haben. OderInt32
was ich gesehen habe. Mit using wirdInt32
eine "Dummy" -Nummer eingeführt (Verwendung0
), aber zumindest können Sie kein großes und exotisches Objekt in eineInt32
Referenz einfügen (Strukturen sind versiegelt).Sie können auch Ihren eigenen "void" -Typ schreiben:
MyVoid
Referenzen sind erlaubt (es ist keine statische Klasse), können aber nur seinnull
. Der Instanzkonstruktor ist privat (und wenn jemand versucht, diesen privaten Konstruktor durch Reflektion aufzurufen, wird eine Ausnahme ausgelöst).Da Werttupel eingeführt wurden (2017, .NET 4.7), ist es möglicherweise natürlich, die Struktur
ValueTuple
(das 0-Tupel, die nicht generische Variante) anstelle eines solchen zu verwendenMyVoid
. Die Instanz hat eineToString()
, die zurückgibt"()"
, sodass sie wie ein Null-Tupel aussieht. Ab der aktuellen Version von C # können Sie die Token()
im Code nicht mehr verwenden , um eine Instanz abzurufen. Sie können stattdessendefault(ValueTuple)
oder nurdefault
(wenn der Typ aus dem Kontext abgeleitet werden kann) verwenden.quelle
Ich mag die Idee von Aleksey Bykov oben, aber sie könnte etwas vereinfacht werden
Da sehe ich keinen offensichtlichen Grund warum Nothing.AtAll nicht einfach null geben konnte
Die gleiche Idee (oder die von Jeppe Stig Nielsen) eignet sich auch hervorragend für typisierte Klassen.
Beispiel, wenn der Typ nur verwendet wird, um die Argumente für eine Prozedur / Funktion zu beschreiben, die als Argument an eine Methode übergeben wurde, und selbst keine Argumente akzeptiert.
(Sie müssen immer noch entweder einen Dummy-Wrapper erstellen oder ein optionales "Nothing" zulassen. Aber meiner Meinung nach sieht die Klassenverwendung mit myClass <Nothing> gut aus.)
oder
quelle
null
hat die Konnotation, dass er fehlt oder fehltobject
. Nur einen Wert für ein zu habenNothing
bedeutet, dass es nie wie etwas anderes aussieht.Nothing
die in einem privaten statischen Feld gespeichert ist und einen privaten Konstruktor hinzufügt. Die Tatsache, dass Null immer noch möglich ist, ist ärgerlich, aber das wird hoffentlich mit C # 8 gelöst.void
Obwohl ein Typ, ist er nur als Rückgabetyp einer Methode gültig.An dieser Einschränkung von führt kein Weg vorbei
void
.quelle
Was ich derzeit mache, ist das Erstellen von benutzerdefinierten versiegelten Typen mit einem privaten Konstruktor. Dies ist besser, als Ausnahmen in den C-Tor zu werfen, da Sie erst zur Laufzeit abrufen müssen, um herauszufinden, ob die Situation falsch ist. Es ist subtil besser als die Rückgabe einer statischen Instanz, da Sie nicht einmal zuordnen müssen. Es ist subtil besser als die Rückgabe der statischen Null, da es auf der Aufrufseite weniger ausführlich ist. Der Anrufer kann nur null angeben.
quelle