Für diejenigen, die nicht die Zeit haben, meine Argumentation für diese Frage zu lesen:
Gibt es eine Möglichkeit, eine Richtlinie für "Nur neue Objekte" oder "Nur vorhandene Objekte" für die Parameter einer Methode durchzusetzen ? ? ? ?
Es gibt viele Methoden, die Objekte als Parameter verwenden, und es spielt keine Rolle, ob die Methode das Objekt "alles für sich" hat oder nicht. Zum Beispiel:
%Vor% Hier hat die Methode List<Person>.Add
ein "existing" Person
(Bob) sowie ein "neues" Person
(Larry) genommen, und die Liste enthält beide Elemente. Bob kann entweder als bob
oder people[0]
aufgerufen werden. Auf Larry kann als people[1]
zugegriffen werden und, falls gewünscht, wird zwischengespeichert und als larry
(oder was auch immer) danach zugegriffen.
OK, gut. Aber manchmal eine Methode sollte nicht ein neues Objekt übergeben werden. Nimm zum Beispiel Array.Sort<T>
. Das Folgende macht keinen großen Sinn:
Der obige Code nimmt ein neues Array, sortiert es und vergisst es dann (da sein Referenzzähler Null erreicht, nachdem Array.Sort<int>
beendet wurde und das sortierte Array daher Müll gesammelt wird, wenn ich mich nicht irre) . Also Array.Sort<T>
erwartet ein "existing" Array als Argument.
Es gibt wahrscheinlich andere Methoden, die "neue" Objekte erwarten können (obwohl ich generell denken würde, dass eine solche Erwartung ein Konstruktionsfehler wäre). Ein unvollkommenes Beispiel wäre das:
%Vor% Wie gesagt, das ist kein großartiges Beispiel, denn DataRowCollection.Add
erwartet eigentlich kein neues DataRow
genau; aber erwartet ein DataRow
, das noch nicht zu einem DataTable
gehört. Die letzte Zeile im obigen Code funktioniert nicht. es muss sein:
Wie auch immer, das ist eine Menge Setup für meine Frage, das heißt: Gibt es eine Möglichkeit, eine Richtlinie für "Nur neue Objekte" oder "Nur existierende Objekte" für die Parameter einer Methode durchzusetzen , entweder in seiner Definition (vielleicht durch einige benutzerdefinierte Attribute, die ich nicht kenne) oder in der Methode selbst (vielleicht durch Reflexion, obwohl ich wahrscheinlich davor zurückschrecken würde, selbst wenn es verfügbar wäre)?
Wenn nicht, wären interessante Ideen, wie dies möglich wäre, mehr als willkommen. Zum Beispiel nehme ich an, wenn es eine Möglichkeit gäbe, die Referenzzählung des GC für ein bestimmtes Objekt zu erhalten, könnten Sie sofort am Anfang einer Methode feststellen, ob Sie ein neues Objekt erhalten haben oder nicht (vorausgesetzt, Sie haben mit Referenztypen zu tun) natürlich - das ist das einzige Szenario, auf das diese Frage ohnehin ankommt.)
BEARBEITEN :
Die längere Version wird länger.
Okay, nehmen wir an, ich habe eine Methode, die ich wahlweise akzeptieren kann, um einen TextWriter
auszugeben, oder um den Fortschritt anzuzeigen:
Sehen wir uns jetzt zwei verschiedene Möglichkeiten an, wie ich diese Methode nennen könnte:
%Vor%ODER:
%Vor% Hmm ... es scheint, dass dies ein Problem darstellt, nicht wahr? Ich habe ein StreamWriter
erstellt, das IDisposable
implementiert, aber TryDoSomething
wird nicht davon ausgehen, zu wissen, ob es exklusiven Zugriff auf sein output
-Argument hat oder nicht. So wird das Objekt entweder vorzeitig entsorgt (im ersten Fall) oder gar nicht entsorgt (im zweiten Fall).
Ich sage nicht, dass das unbedingt ein großartiges Design wäre. Vielleicht hat Josh Stodola recht und das ist von Anfang an nur eine schlechte Idee. Jedenfalls habe ich die Frage hauptsächlich gestellt, weil ich nur neugierig war, ob so etwas möglich ist. Sieht aus wie die Antwort ist: nicht wirklich.
Nein, grundsätzlich.
Es gibt wirklich keinen Unterschied zwischen:
%Vor%und
%Vor%und in der Tat könnten Sie manchmal zwischen den beiden zu Debugging-Zwecken konvertieren.
Beachten Sie, dass es im Beispiel DataRow
/ DataTable
jedoch einen alternativen Ansatz gibt - dass DataRow sein Elternelement als Teil seines Status kennen kann. Das ist nicht dasselbe wie "neu" oder nicht - Sie könnten zum Beispiel eine "detach" Operation haben. Bedingungen in Bezug auf den echten Hard-und-Fast-Zustand des Objekts zu definieren, ist viel sinnvoller als wollige Begriffe wie "neu".
Ja, es gibt eine Möglichkeit, dies zu tun.
Sortieren von.
Wenn Sie Ihren Parameter zu einem ref
-Parameter machen, müssen Sie eine existierende Variable als Argument haben. Sie können so etwas nicht tun:
Wenn Sie dies tun, erhalten Sie den Fehler "Ein Ref- oder Out-Argument muss eine zuweisbare Variable sein."
Natürlich hat die Verwendung von ref andere Implikationen. Wenn Sie jedoch der sind, der die Methode schreibt, müssen Sie sich keine Gedanken darüber machen. Solange Sie den Ref-Parameter nicht innerhalb der Methode neu zuweisen, macht es keinen Unterschied, ob Sie ref verwenden oder nicht.
Ich sage nicht, dass es ein guter Stil ist, unbedingt. Du solltest ref oder out nicht verwenden, es sei denn, du musst wirklich, wirklich, und hast keine andere Möglichkeit, das zu tun, was du tust. Aber mit ref machen Sie was Sie tun wollen.
Nein, grundsätzlich.
Es gibt wirklich keinen Unterschied zwischen:
%Vor%und
%Vor%und in der Tat könnten Sie manchmal zwischen den beiden zu Debugging-Zwecken konvertieren.
Beachten Sie, dass es im Beispiel %code% / %code% jedoch einen alternativen Ansatz gibt - dass DataRow sein Elternelement als Teil seines Status kennen kann. Das ist nicht dasselbe wie "neu" oder nicht - Sie könnten zum Beispiel eine "detach" Operation haben. Bedingungen in Bezug auf den echten Hard-und-Fast-Zustand des Objekts zu definieren, ist viel sinnvoller als wollige Begriffe wie "neu".
Für diejenigen, die nicht die Zeit haben, meine Argumentation für diese Frage zu lesen:
Gibt es eine Möglichkeit, eine Richtlinie für "Nur neue Objekte" oder "Nur vorhandene Objekte" für die Parameter einer Methode durchzusetzen ? ? ? ?
Es gibt viele Methoden, die Objekte als Parameter verwenden, und es spielt keine Rolle, ob die Methode das Objekt "alles für sich" hat oder nicht. Zum Beispiel:
%Vor%Hier hat die Methode %code% ein "existing" %code% (Bob) sowie ein "neues" %code% (Larry) genommen, und die Liste enthält beide Elemente. Bob kann entweder als %code% oder %code% aufgerufen werden. Auf Larry kann als %code% zugegriffen werden und, falls gewünscht, wird zwischengespeichert und als %code% (oder was auch immer) danach zugegriffen.
OK, gut. Aber manchmal eine Methode sollte nicht ein neues Objekt übergeben werden. Nimm zum Beispiel %code% . Das Folgende macht keinen großen Sinn:
%Vor%Der obige Code nimmt ein neues Array, sortiert es und vergisst es dann (da sein Referenzzähler Null erreicht, nachdem %code% beendet wurde und das sortierte Array daher Müll gesammelt wird, wenn ich mich nicht irre) . Also %code% erwartet ein "existing" Array als Argument.
Es gibt wahrscheinlich andere Methoden, die "neue" Objekte erwarten können (obwohl ich generell denken würde, dass eine solche Erwartung ein Konstruktionsfehler wäre). Ein unvollkommenes Beispiel wäre das:
%Vor%Wie gesagt, das ist kein großartiges Beispiel, denn %code% erwartet eigentlich kein neues %code% genau; aber erwartet ein %code% , das noch nicht zu einem %code% gehört. Die letzte Zeile im obigen Code funktioniert nicht. es muss sein:
%Vor%Wie auch immer, das ist eine Menge Setup für meine Frage, das heißt: Gibt es eine Möglichkeit, eine Richtlinie für "Nur neue Objekte" oder "Nur existierende Objekte" für die Parameter einer Methode durchzusetzen , entweder in seiner Definition (vielleicht durch einige benutzerdefinierte Attribute, die ich nicht kenne) oder in der Methode selbst (vielleicht durch Reflexion, obwohl ich wahrscheinlich davor zurückschrecken würde, selbst wenn es verfügbar wäre)?
Wenn nicht, wären interessante Ideen, wie dies möglich wäre, mehr als willkommen. Zum Beispiel nehme ich an, wenn es eine Möglichkeit gäbe, die Referenzzählung des GC für ein bestimmtes Objekt zu erhalten, könnten Sie sofort am Anfang einer Methode feststellen, ob Sie ein neues Objekt erhalten haben oder nicht (vorausgesetzt, Sie haben mit Referenztypen zu tun) natürlich - das ist das einzige Szenario, auf das diese Frage ohnehin ankommt.)
BEARBEITEN :
Die längere Version wird länger.
Okay, nehmen wir an, ich habe eine Methode, die ich wahlweise akzeptieren kann, um einen %code% auszugeben, oder um den Fortschritt anzuzeigen:
%Vor%Sehen wir uns jetzt zwei verschiedene Möglichkeiten an, wie ich diese Methode nennen könnte:
%Vor%ODER:
%Vor%Hmm ... es scheint, dass dies ein Problem darstellt, nicht wahr? Ich habe ein %code% erstellt, das %code% implementiert, aber %code% wird nicht davon ausgehen, zu wissen, ob es exklusiven Zugriff auf sein %code% -Argument hat oder nicht. So wird das Objekt entweder vorzeitig entsorgt (im ersten Fall) oder gar nicht entsorgt (im zweiten Fall).
Ich sage nicht, dass das unbedingt ein großartiges Design wäre. Vielleicht hat Josh Stodola recht und das ist von Anfang an nur eine schlechte Idee. Jedenfalls habe ich die Frage hauptsächlich gestellt, weil ich nur neugierig war, ob so etwas möglich ist. Sieht aus wie die Antwort ist: nicht wirklich.
Kurze Antwort - nein, es gibt keine
In der überwiegenden Mehrzahl der Fälle finde ich normalerweise, dass die Probleme, die Sie oben aufgelistet haben, nicht so wichtig sind. Wenn dies der Fall ist, könnten Sie eine Methode überladen, so dass Sie etwas anderes als Parameter anstelle des Objekts, das Sie sich teilen möchten, akzeptieren.
%Vor%Ich kann mir einen Weg vorstellen, dies zu tun, aber ich würde das definitiv nicht empfehlen. Nur um der Sache willen.
Was bedeutet es für ein Objekt, ein "neues" Objekt zu sein? Es bedeutet, dass es nur eine Referenz gibt, die es am Leben erhält. Ein "existierendes" Objekt würde mehr als eine Referenz darauf haben.
Betrachten Sie in diesem Zusammenhang den folgenden Code:
%Vor%Dies zeigt True in der ersten Zeile, False in der zweiten Zeile an. Aber bitte, benutze das nicht in deinem Code.
Lassen Sie mich Ihre Frage etwas kürzer schreiben.
Gibt es in meiner Methode einen Weg, der ein Objekt als Argument nimmt, um zu wissen, ob dieses Objekt jemals außerhalb meiner Methode verwendet wird?
Und die kurze Antwort darauf lautet: Nein.
Lassen Sie mich an dieser Stelle eine Meinung wagen: Es sollte auch keinen solchen Mechanismus geben.
Dies würde Methodenaufrufe überall erschweren.
Wenn es eine Methode gäbe, bei der ich in einem Methodenaufruf sagen könnte, ob das Objekt, das mir gegeben wurde, wirklich benutzt wird oder nicht, dann ist es ein Signal für mich, als Entwickler dieser Methode das zu übernehmen Konto.
Im Prinzip würden Sie diese Art von Code überall sehen (hypothetisch, da nicht verfügbar / unterstützt:)
%Vor%Meine Meinung ist folgende: Wenn der Code, den aufruft, die Methode nicht für irgendetwas verwendet und es keine Nebeneffekte außerhalb der Modifizierung des Objekts gibt, dann sollte dieser Code zu Beginn nicht vorhanden.
Es ist wie Code, der so aussieht:
%Vor%Was macht dieser Code? Nun, abhängig vom C / C ++ - Compiler kann in etwas kompiliert werden, das 1 + 2 auswertet. Aber was, wo wird das Ergebnis gespeichert? Benutzt du es für irgendetwas? Nein? Warum ist dann dieser Code Teil Ihres Quellcodes?
Natürlich könnten Sie argumentieren, dass der Code tatsächlich %code% ist, und der Zweck ist sicherzustellen, dass die Auswertung von %code% keine Ausnahme ausgibt, die Überlauf anzeigt, aber ein solcher Fall ist so selten dass ein spezieller Fall dafür echte Probleme maskiert, und es wäre wirklich einfach zu beheben, indem man es nur einer temporären Variable zuweist.
In jedem Fall sind für jedes Feature in einer Programmiersprache und / oder Laufzeit und / oder Umgebung, in dem eine Funktion nicht verfügbar ist, die Gründe dafür, warum sie nicht verfügbar ist:
Alle diese sind erforderlich, um ein Feature zu erhalten, das in Version X von Anwendung Y angezeigt wird, sei es C # 4.0 oder MS Works 7.0.
Nein, das kann man nicht wissen.
Alles was übergeben wird, ist die Objektreferenz. Unabhängig davon, ob es in situ "neu erstellt" wird oder aus einem Array stammt, kann die fragliche Methode nicht wissen, wie die übergebenen Parameter instanziiert wurden und / oder wo.
Eine Möglichkeit festzustellen, ob ein Objekt, das an eine Funktion (oder eine Methode) übergeben wurde, direkt vor dem Aufruf der Funktion / Methode erstellt wurde, ist, dass das Objekt eine Eigenschaft hat, die mit dem von einer Systemfunktion übergebenen Zeitstempel initialisiert wird; Auf diese Weise wäre es möglich, das Problem zu lösen.
Ehrlich gesagt, würde ich solche Methode nicht verwenden, weil
Die andere Lösung wäre, eine Objekteigenschaft zu verwenden, die auf einen Wert vom Ersteller des Objekts festgelegt ist und der auf einen anderen Wert als alle Methoden des Objekts festgelegt ist.
In diesem Fall würde das Problem darin bestehen, zu vergessen, den Code hinzuzufügen, um diese Eigenschaft in jeder Methode zu ändern.
Noch einmal würde ich mich selbst fragen: "Ist es wirklich nötig, das zu tun?".
Als mögliche Teillösung, wenn Sie nur eines von einem Objekt wünschen, das von einer Methode konsumiert wird, könnten Sie sich vielleicht ein Singleton anschauen. Auf diese Weise konnte die betreffende Methode keine andere Instanz erstellen, wenn sie bereits existierte.
Ja, es gibt eine Möglichkeit, dies zu tun.
Sortieren von.
Wenn Sie Ihren Parameter zu einem %code% -Parameter machen, müssen Sie eine existierende Variable als Argument haben. Sie können so etwas nicht tun:
%Vor%Wenn Sie dies tun, erhalten Sie den Fehler "Ein Ref- oder Out-Argument muss eine zuweisbare Variable sein."
Natürlich hat die Verwendung von ref andere Implikationen. Wenn Sie jedoch der sind, der die Methode schreibt, müssen Sie sich keine Gedanken darüber machen. Solange Sie den Ref-Parameter nicht innerhalb der Methode neu zuweisen, macht es keinen Unterschied, ob Sie ref verwenden oder nicht.
Ich sage nicht, dass es ein guter Stil ist, unbedingt. Du solltest ref oder out nicht verwenden, es sei denn, du musst wirklich, wirklich, und hast keine andere Möglichkeit, das zu tun, was du tust. Aber mit ref machen Sie was Sie tun wollen.
Kurze Antwort - nein, es gibt keine
In der überwiegenden Mehrzahl der Fälle finde ich normalerweise, dass die Probleme, die Sie oben aufgelistet haben, nicht so wichtig sind. Wenn dies der Fall ist, könnten Sie eine Methode überladen, so dass Sie etwas anderes als Parameter anstelle des Objekts, das Sie sich teilen möchten, akzeptieren.
%Vor%Ich kann mir einen Weg vorstellen, dies zu tun, aber ich würde das definitiv nicht empfehlen. Nur um der Sache willen.
Was bedeutet es für ein Objekt, ein "neues" Objekt zu sein? Es bedeutet, dass es nur eine Referenz gibt, die es am Leben erhält. Ein "existierendes" Objekt würde mehr als eine Referenz darauf haben.
Betrachten Sie in diesem Zusammenhang den folgenden Code:
%Vor%Dies zeigt True in der ersten Zeile, False in der zweiten Zeile an. Aber bitte, benutze das nicht in deinem Code.
Lassen Sie mich Ihre Frage etwas kürzer schreiben.
Gibt es in meiner Methode einen Weg, der ein Objekt als Argument nimmt, um zu wissen, ob dieses Objekt jemals außerhalb meiner Methode verwendet wird?
Und die kurze Antwort darauf lautet: Nein.
Lassen Sie mich an dieser Stelle eine Meinung wagen: Es sollte auch keinen solchen Mechanismus geben.
Dies würde Methodenaufrufe überall erschweren.
Wenn es eine Methode gäbe, bei der ich in einem Methodenaufruf sagen könnte, ob das Objekt, das mir gegeben wurde, wirklich benutzt wird oder nicht, dann ist es ein Signal für mich, als Entwickler dieser Methode das zu übernehmen Konto.
Im Prinzip würden Sie diese Art von Code überall sehen (hypothetisch, da nicht verfügbar / unterstützt:)
%Vor%Meine Meinung ist folgende: Wenn der Code, den aufruft, die Methode nicht für irgendetwas verwendet und es keine Nebeneffekte außerhalb der Modifizierung des Objekts gibt, dann sollte dieser Code zu Beginn nicht vorhanden.
Es ist wie Code, der so aussieht:
%Vor%Was macht dieser Code? Nun, abhängig vom C / C ++ - Compiler kann in etwas kompiliert werden, das 1 + 2 auswertet. Aber was, wo wird das Ergebnis gespeichert? Benutzt du es für irgendetwas? Nein? Warum ist dann dieser Code Teil Ihres Quellcodes?
Natürlich könnten Sie argumentieren, dass der Code tatsächlich a+b;
ist, und der Zweck ist sicherzustellen, dass die Auswertung von a+b
keine Ausnahme ausgibt, die Überlauf anzeigt, aber ein solcher Fall ist so selten dass ein spezieller Fall dafür echte Probleme maskiert, und es wäre wirklich einfach zu beheben, indem man es nur einer temporären Variable zuweist.
In jedem Fall sind für jedes Feature in einer Programmiersprache und / oder Laufzeit und / oder Umgebung, in dem eine Funktion nicht verfügbar ist, die Gründe dafür, warum sie nicht verfügbar ist:
Alle diese sind erforderlich, um ein Feature zu erhalten, das in Version X von Anwendung Y angezeigt wird, sei es C # 4.0 oder MS Works 7.0.
Nein, das kann man nicht wissen.
Alles was übergeben wird, ist die Objektreferenz. Unabhängig davon, ob es in situ "neu erstellt" wird oder aus einem Array stammt, kann die fragliche Methode nicht wissen, wie die übergebenen Parameter instanziiert wurden und / oder wo.
Eine Möglichkeit festzustellen, ob ein Objekt, das an eine Funktion (oder eine Methode) übergeben wurde, direkt vor dem Aufruf der Funktion / Methode erstellt wurde, ist, dass das Objekt eine Eigenschaft hat, die mit dem von einer Systemfunktion übergebenen Zeitstempel initialisiert wird; Auf diese Weise wäre es möglich, das Problem zu lösen.
Ehrlich gesagt, würde ich solche Methode nicht verwenden, weil
Die andere Lösung wäre, eine Objekteigenschaft zu verwenden, die auf einen Wert vom Ersteller des Objekts festgelegt ist und der auf einen anderen Wert als alle Methoden des Objekts festgelegt ist.
In diesem Fall würde das Problem darin bestehen, zu vergessen, den Code hinzuzufügen, um diese Eigenschaft in jeder Methode zu ändern.
Noch einmal würde ich mich selbst fragen: "Ist es wirklich nötig, das zu tun?".
Als mögliche Teillösung, wenn Sie nur eines von einem Objekt wünschen, das von einer Methode konsumiert wird, könnten Sie sich vielleicht ein Singleton anschauen. Auf diese Weise konnte die betreffende Methode keine andere Instanz erstellen, wenn sie bereits existierte.
Tags und Links .net c# reference new-operator parameters