Frage

Ich bin fest mit .NET 1.1-Anwendung (das heißt ich kann das Generika-Goodies von 2.0 jetzt verwenden), und ich habe versucht, einige Teile des Codes zu optimieren. Da es viel mit Laufzeit aufrufbare Wrapper beschäftigt, die gelöst werden müssen, landete ich eine Hilfsmethode zu schaffen, bis alle Verweise Schleife freigegeben werden. Die Signatur der Methode ist:

void ReleaseObject(object comObject)

Nachdem alle comObjects Loslassen, ich nenne GC.Collect und GC.WaitForPendingFinalizers (nicht fragen - jemand mit Office Interop Umgang weiß).

Und ... wie üblich, ich traf eine Ecke Fall -. Wenn ich den entsprechenden verwalteten Verweis auf null vor dem GC.Collect Anruf nicht zuordnen, spielt es keine Bereinigungs richtig

Also, mein Code wie folgt aussieht:

ReleaseObject(myComObject);
myComObject = null;
GC.Collect()
...

Da es eine Reihe von xxx = null ist, habe ich beschlossen, diese in der util Methode zu setzen, aber da es ein Unterschied zwischen vorbei Referenz, und ein Referenz-Parameter übergibt, natürlich musste ich die Methode ändern:

void ReleaseObject(out object comObject)
{
   //do release
   comObject = null;
}

und bearbeiten Sie den Anrufer an:

MyComClass myComObject = xxxx;
ReleaseObject(out myComObject);

Dies scheitert mit einer Nachricht: „Kann von‚out MyComClass‘auf‚out-Objekt‘nicht konvertieren“

Während ich denken kann, warum es ein Problem sein kann (dh die umgekehrte Besetzung von Objekt zu MyComClass ist nicht implizit, und es gibt keine Garantie, was die Methode übernommen werden kann), ich frage mich, ob es eine Abhilfe ist, oder ich muß mit meinen Hunderten Zuweisungen von Nullen bleiben.

. Hinweis: Ich habe eine Reihe von verschiedenen COM-Objekte Typen, das ist, warum ich ein „Objekt“ Parameter benötigen, und nicht eine Art sicher ein

War es hilfreich?

Lösung

Warum ist es besser, ein Verfahren als rufen, um nur die Variable auf null gesetzt? Sie sind beide Single Linie nennt, und dieser ist viel einfacher.

Es klingt sehr seltsam, dass man sie auf null in erster Linie allerdings einstellen müssen. Sind diese statischen Variablen oder Instanzvariablen, deren Werte müssen früher freigegeben werden als ihr enthalten Objekt? Wenn die Variable nur eine lokale Variable ist, die ohnehin den Gültigkeitsbereich verlassen wird, ist es Einstellung auf Null sollte keinen Unterschied machen (in Version).

Sie implementieren die RCWs nicht IDisposable? Wenn ja, ruft Dispose (vorzugsweise über eine using-Anweisung) wäre die beste Wette.

(Nach Diskussionen in den Kommentaren.)

Dies sind lokale Variablen, die nicht später in dem Verfahren verwiesen. Das bedeutet, dass der Garbage Collector wird erkennen, dass sie nicht brauchen, als „root“ Referenzen behandelt werden -. So sie Einstellung nicht auf Null sollte keinen Unterschied machen

die ursprüngliche Frage zu beantworten, direkt, aber: nein, können Sie keine Variable als Verweis übergeben, wenn der Methodenparameter von genau der gleichen Art ist, so dass Sie hier kein Glück. (Mit Generika wäre es möglich sein, aber Sie haben gesagt sind Sie beschränkt auf .NET 1.1.)

Andere Tipps

Sunny, ref und out sind ein Rangier Hinweise + Vertrag an den Compiler. Ref und out sind eine Verschleppung zu COM Tagen - die Rangierung Hinweise für Objekte, wenn sie über den Draht / zwischen Prozessen gesendet

.

Der out Vertrag

void foo( out MyClass x)
  1. foo () wird x auf etwas setzen, bevor er zurückkehrt.
  2. x hat keinen Wert, wenn foo () eingegeben wird, und Sie einen Compiler-Fehler erhalten, wenn Sie x zu verwenden, bevor Sie es versuchen. (Verwendung von nicht zugeordneten out-Parameter x)

Der ref Vertrag

void foo( ref MyClass x)
  1. ref ermöglicht es dem Anrufer Referenz zu ändern.
  2. x hat sein zuweisbare
    • Sie können etwas nicht zu einer Zwischengröße foo (ref (Objekt) etwas)
    • gegossen
    • x kann nicht eine Eigenschaft sein

Die Realität der letzten beiden Punkte sind wahrscheinlich, Sie zu stoppen tun, was Sie zu tun versuchen, denn in der Tat sie keinen Sinn machen, wenn Sie verstehen, was wirklich referenziert sind. Wenn Sie das wissen wollen, fragen Jon Skeet (er schrieb ein Buch).

Wenn ref Rangier-, heißt es, dass auf den Rückgabewert zusätzlich auch ref Werte bringen. Wenn Rangier-out, sagt es nicht die Mühe den Überschreitungswert zu senden, wenn die Methode aufgerufen wird, aber nicht vergessen, den Überschreitungswert zusätzlich zu dem Rückgabewert zu bringen.


HAFTUNGSAUSSCHLUSS HAFTUNGSAUSSCHLUSS HAFTUNGSAUSSCHLUSS

Wie andere weisen darauf hin, etwas faul vor sich geht. Es scheint, die Brute-Force-Code, den Sie hat einige subtile Fehler pflegen und leidet durch Zufall von Codierung. Die beste Lösung ist wahrscheinlich eine weitere Schicht von Dereferenzierung hinzuzufügen. das heißt ein Wrapper für die Wrapper-Klasse, die deterministische Bereinigung sorgt dafür, wo Sie einmal den chaotischen Code schreiben können und nur einmal, statt es in Ihrer Code-Basis Würzen.


Wie gesagt ..

Alternative 1

Ref wird der Trick nicht tun, wenn Sie Überlastungen für jede Art von (com) Objekt bieten rufen Sie es mit.

// need a remove method for each type. 
void Remove( ref Com1 x ) { ...; x = null; }
void Remove( ref Con2 x ) { ...; x = null; }
void Remove( ref Com3 x ) { ...; x = null; }

// a generics version using ref.
void RemoveComRef<ComT>(ref ComT t) where ComT : class
{
    System.Runtime.InteropServices.Marshal.ReleaseComObject(t);
    t = null; 
}

Com1 c1 = new Com1();
Com2 c2 = new Com2();
Remove( ref c1 );
RemoveComRef(ref c2); // the generics version again.

Alternative 2

Wenn Sie das nicht tun wollen, null zurück aus dem Remove () -Methode und zurückgeworfen auf die Art des Objekts.

class Remover
{
    // .net 1.1 must cast if assigning
    public static object Remove(object x)
    {
        System.Runtime.InteropServices.Marshal.ReleaseComObject(x);
        return null;
    }

    // uses generics.
    public static ComT RemoveCom<ComT>(ComT t) where ComT : class
    {
        System.Runtime.InteropServices.Marshal.ReleaseComObject(t);
        return null;
    }   
}

Com1 c1 = new Com1();
Com2 c2 = new Com2();
c1 = (Com1)Remover.Remove(c1); // no reliance on generics
c2 = Remover.RemoveCom(c2); // relies on generics

* Ich habe generische Versionen zum Vergleich.

Der obige Code hat den Effekt, dass, wenn im Code suchen Sie misstrauisch, wenn Sie einen Anruf sehen entfernen (x) ohne Zuordnung (falschen Code aussieht falsch machen). Man könnte sogar durch die Code-Basis grep für Anrufe der Suche zu entfernen, wo Zuordnung findet nicht statt.


HAFTUNGSAUSSCHLUSS -. Alle oben ausgesagt wird auf Ihrem benötigen Sie den Verweis auf manuell eingestellt auf Null, die (in der Regel) nicht erforderlich

Meiner Meinung nach werden Sie die Objekte auf Null gesetzt in einer anderen Methode nicht in der Lage sein (BTW müssen Sie verwenden ref Parameter anstelle von aus machen arbeiten, ohnehin würden Sie das gleiche Problem mit hit „Kann nicht konvertieren ...“ Fehler.) Ich würde empfehlen, Objekte zu erstellen und Array von und als durch das Array durchlaufen, die ReleaseObject Methode aufrufen und diese Objekte Einstellung auf null. So etwas wie:

List garbagedObjects = new List();
garbagedObjects.Add(myComObject1);
garbagedObjects.Add(myComObject2);
...
foreach(object garbagedObject in garbagedObjects)
{
  ReleaseObject(garbagedObject);
  garbagedObject = null;
}
garbagedObjects = null;
GC.Collect();
...

Sie sollten anrufen Marshal.ReleaseComObject , die AFAIK war in 1.1 zur Verfügung.

Du meinst wahrscheinlich "ref":

static void ReleaseObject(ref object comObject)
{
   if(comObject != null)
   {
     //do release
     comObject = null;
   }
}

[Bearbeiten re Kommentare] wird dies jedoch nur für nicht typisierten Objekten arbeiten, so dass nicht viel ohne Generika! Oh für C # 2.0 ...

Re der "ref"; wenn die Variablen wirklich Variablen (Bedeutung: Methode Variablen) sind, dann werden sie in Kürze den Gültigkeitsbereich verlassen und gesammelt bekommen. Die „ref“ wäre nur sinnvoll sein, Felder zu lösen. Aber um ehrlich zu sein, wäre es einfacher, nur um sie zu auf null ...

Ein typisches COM Muster:

SomeType obj = new SomeType();
try {
  obj.SomeMethod(); // etc
} finally {
  Marshal.ReleaseComObject(obj);
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top