2012-05-10 3 views
5

Ran in ein interessantes Problem, das ich mich fragte, ob jemand helfen kann zu erklären. Ich habe versucht, überall im Internet zu suchen und finde keine Antwort auf dieses Problem. Während wir eine Lösung haben, können andere auf das gleiche Problem stoßen, und da es zufällig war, ist es sehr schwer zu finden.Marshalling "als Zeichenfolge" -Parameter von C#

Wir haben eine Anwendung, die zufällig fehlschlägt, wenn der Computer an das Firmennetzwerk des Kunden angeschlossen ist (haben Sie nicht viele Informationen über das Netzwerk). Als wir den Computer in unsere Umgebung brachten, funktionierte es gut. Der Fehler ist ziemlich zufällig, aber so gut wie ich herausfinden konnte, trat während Anrufen von C# zu einer nicht verwalteten Drittanbieter-DLL auf. Eine der Trace-Backs, die ich habe (nur ein paar Fehler im Systemereignisprotokoll), weist auf einen Fehler in ntdll.dll in der RtlMoveMemory-Funktion während des Marshalling von Parametern in Aufrufen der nicht verwalteten DLL hin.

Der Aufruf an die nicht verwaltete Funktion war:

ThirdParty.CxxxAutomationWrapper clientDLL = new ThirdParty.CxxxAutomationWrapper() ; 

object Parameter1 ; 
    : 
string theValue = "abcde" ; 
Parameter1 = theValue ; 
    : 
if (Parameter1 is string) 
{ 
    int returnCode = clientDLL.function (Parameter1 as string) ; 
} 

Der Anruf nicht regelmäßig auf dem Computer Kunden aber funktioniert immer, wenn in Visual Studio (2010) laufen. Der Wert von Parameter1 ist korrekt festgelegt (nie null).

Da ich den Aufruf geändert:

String parameter1String = Parameter1.ToString() ; 
int returnCode = clientDLL.function (parameter1String) ; 

alles hat geklappt hat. Der Wert von Parameter1 wird sehr kontrolliert und ist vor der Ausführung dieses Codes nicht null.

Die Schnittstelle (clientDLL.function) genannt wird, ist wie folgt definiert: [? Eingeschränkt]

HRESULT function ([in] BSTR parameter, 
        [out, retval] long *ret); 

Mit meinem Verständnis für die ‚als‘ Aussage in C#, ich verstehe nicht, warum die erste Version von das ist fehlgeschlagen. Kann jemand erklären, warum dies fehlschlägt, wenn es mit dem als "as string" angegebenen Parameter aufgerufen wird?

+0

Aktualisierte den ursprünglichen Post als Antwort auf Antworten, die ich erhielt, um das Problem zu klären. Zu den Updates gehört das Anzeigen, wie Parameter1 deklariert und zugewiesen wird, und das Einfügen eines if (Parameter1 ist eine Zeichenfolge) um den Aufruf, wie von Tudor vorgeschlagen. –

+0

Können Sie versuchen, zu protokollieren, für welche Werte von 'Parameter1' der Absturz auftritt? Kannst du irgendein Muster sehen? – Tudor

+0

Ich habe den genauen oben gezeigten Code codiert, die Zuweisung zu einer String-Variable fest programmiert, sie mit "abcde" initialisiert und diese Variable dem Parameter1 zugewiesen, indem ich sie über if (Parameter1 ist eine Zeichenkette) getestet habe und trotzdem in Visual Studio funktioniert von VS (manchmal). –

Antwort

5

Weil obj as string und obj.ToString() nicht identisch sind. Die erste ist eine versuchte Umwandlung (eine Art wie (string)obj, die aber bei einem Fehler null zurückgibt), während die Sekunden ein Methodenaufruf ist, der eine Zeichenfolgendarstellung des Objekts zurückgibt.

Praktisch können Sie die Zeichenfolgendarstellung eines beliebigen Objekts abrufen, unabhängig davon, ob es mit String als Typ kompatibel ist, aber die Umwandlung schlägt fehl, wenn sie nicht kompatibel sind.

einfaches Beispiel:

object obj = new object(); // simple object 
Console.WriteLine(obj.ToString()); // prints System.Object 
Console.WriteLine((obj as string) == null); // True: obj is not a string! 
+0

Ich habe seitdem meinen Beispielcode aktualisiert, um zu zeigen, dass Parameter1 immer ein gültiges Zeichenfolgenobjekt enthält. Außerdem habe ich Probleme mit der Zufälligkeit des Fehlers und der Tatsache, dass in Visual Studio kein Problem auftritt. –

+0

@RichardBousman: So sind Sie sicher, dass 'Parameter1' immer eine gültige Zeichenfolge ist? Ich könnte die Situation, die Sie erwähnt haben, sehen, falls Sie manchmal versehentlich eine Nicht-Zeichenfolge übergeben, so dass 'as string' fehlschlägt, aber' ToString' nicht. – Tudor

+0

Ja. Wenn es nicht wäre, würde ich 1) immer versagen 2) in Visual Studio fehlschlagen. Der Parameter wird vor diesem Zeitpunkt mehrmals überprüft. Der Code, auf den oben verwiesen wird, befindet sich in einer DLL. Der Code befindet sich in einer verwalteten DLL. Die Zeichenfolge wird ursprünglich von einer nicht verwalteten C++ - DLL an die verwaltete DLL übergeben. –

2

Parameter1.ToString() rendert .NET-Objekt in eine Zeichenfolge (d.h. Instanz von System.String). Parameter1 as string wird null zurückgeben, wenn Parameter1 null ist oder wenn es keine Instanz von System.String ist. Wenn es sich um eine Klasse handelt, die eine Zeichenkette statt umschließt, dann werden Sie mit einer null enden.

Weder wird in jedem Fall natürlich funktionieren. Wenn Sie eine Instanz von System.String haben, die null ist, dann würde Parameter1 as stringnull korrekt zurückgeben, während Parameter1.ToString() eine NullReferenceException werfen würde.

Ein sicherer Ansatz wäre: Convert.ToString(Parameter1).

+0

Danke für die Antwort. Ich habe seitdem den ursprünglichen Beitrag aktualisiert, um zu zeigen, dass Parameter1 immer eine gültige Zeichenfolge ist. –

0

Parameter1 as string könnte man sich als

string foo 
try 
{ 
    foo = (string)Parameter1; 
} 
catch 
{ 
    foo = null; 
} 

wo .ToString() ist

string foo = Parameter1.ToString(); 

Die Tatsache, dass Parameter1 in einen String nicht direkt gießbaren ist die reson dafür versagt.