2015-06-26 3 views
5

Ich habe Funktion in C++ so etwas wie diese optionalen Zeiger Argument konvertieren:Wie aus C++ Code zu C#

// C++ 
bool Foo(int* retVal = NULL) 
{ 
    // ... 
    if (retVal != NULL) 
     *retVal = 5; 
    // ... 
    return true; 
} 

Und ich kann auf zwei Arten verwendet Funktionen:

int ret; 
Foo(&ret); 

Foo(); 

Wenn ich Code schreiben I in C# verwendet ref Stichwort:

// C# 
bool Foo(ref int retVal = null) 
{ 
    // ... 
    if (retVal != null) 
    { 
     retVal = 5; 
    } 
    // ... 
    return true; 
} 

aber Compiler sagte:

Ein Ref- oder Out-Parameter kann keinen Standardwert haben.

Wie kann ich dieses Problem lösen?

+3

Sie könnten einen Nullable-Typ wie 'int?' Verwenden. Siehe: https://msdn.microsoft.com/en-us/library/2cf62fcy.aspx – NathanOliver

+0

@NathanOliver Beachten Sie, dass dies funktioniert für 'ref int', für Parameter wie' ref string' das funktioniert nicht – xanatos

+0

@ xanatos sind keine Zeichenfolgen, die standardmäßig in C# als NULL-Zeichen gesetzt werden können, so dass Sie '?' nicht verwenden müssen. – NathanOliver

Antwort

3

Die einfachste Weise nur wäre eine Überlastung schreiben:

bool Foo() 
{ 
    int notUsed; 
    return Foo(ref notUsed); 
} 

bool Foo(ref int retVal) 
{ 
    // ... 
    retVal = 5; 
    // ... 
    return true; 
} 

Wenn Sie tatsächlich müssen wissen, ob der ref Wert benötigt wird, na ja, Sie noch Zeiger verwenden können, aber Sie werden einen unsafe Kontext benötigen:

unsafe bool Foo() 
{ 
    return Foo(null); 
} 

unsafe bool Foo(ref int retVal) 
{ 
    return Foo(&retVal); 
} 

private unsafe bool Foo(int* retVal) 
{ 
    // ... 
    if (retVal != null) 
    { 
     *retVal = 5; 
    } 
    // ... 
    return true; 
} 

Oder ohne unsafe wie in den Kommentaren vorgeschlagen, als Zeiger in C# als schwere Artillerie kann in Betracht gezogen werden:

bool Foo() 
{ 
    var notNeeded = 0; 
    return Foo(ref notNeeded, false); 
} 

bool Foo(ref int retVal) 
{ 
    return Foo(ref retVal, true); 
} 

private bool Foo(ref int retVal, bool retValNeeded) 
{ 
    // ... 
    if (retValNeeded) 
    { 
     retVal = 5; 
    } 
    // ... 
    return true; 
} 
+0

Ich dachte das gleiche (meine erste Revision war die gleiche http://stackoverflow.com/revisions/31075073/1). Aber dann habe ich gemerkt, dass wir hier Informationen verlieren ... Die C - Version kann unterscheiden, ob "retVal *" übergeben wurde oder nicht, und vielleicht eine schwere Berechnung, um sie zurückzugeben, während die C# es nicht kann ... C# -Version ist reiner syntaktischer Zucker, um die Methode leichter aufrufen zu können. – xanatos

+0

@xanatos Ja, ich habe bemerkt, dass 'wenn' im ursprünglichen Code ... Ich schreibe einen zweiten Weg. –

+1

Unsicherer Code ... Bitte tu das nicht ... Denk an die Kinder!:-) Wenn du wirklich willst, könntest du ein Array von einem Element übergeben ... Oder besser gesagt einfach einen zusätzlichen 'Bool'-Parameter. Sie schützen die "echte" Methode bereits mit zwei Methoden ... Fügen Sie der realen Methode einen 'bool' hinzu. – xanatos

3

Die ref von C# ähnelt eher der & (Referenz) von C++ als die * von C und C++ (Zeiger). Wie C++ verweist, müssen sie auf etwas verweisen.

Nun konnte man:

public class OptionalRef<T> 
{ 
    public T Value { get; set; } 

    public static implicit operator OptionalRef<T>(T value) 
    { 
     return new OptionalRef<T> { Value = value }; 
    } 

    public static implicit operator T(OptionalRef<T> optional) 
    { 
     return optional.Value; 
    } 

    public override string ToString() 
    { 
     return Value != null ? Value.ToString() : null; 
    } 
} 

dann

static bool Foo(OptionalRef<int> retVal = null) 
{ 
    // ... 
    if (retVal != null) 
    { 
     retVal.Value = 5; 
    } 
    // ... 
    return true; 
} 

und verwenden Sie es mögen:

Foo(); // null passed 
Foo(null); // same 

Foo(5); // not interested if the value is changed 

// Full use 
OptionalRef<int> val = 5; 
Foo(val); 
int ret = val; 

beachten Sie, dass ich nicht in vollem Umfang die Semantik Billigung ich schrieb

Es ist mehr ein Fall von ist sie etwas fragte, gab ich dir etwas, keine Fragen gestellt

+0

Ich mag Ihren Haftungsausschluss. Können Sie näher darüber nachdenken, was Sie darüber denken? Sie müssen es nicht in Ihre Antwort schreiben, aber gibt es eine bessere Möglichkeit, dies zu tun, oder magst du die Ref-Lösung? – thinklarge

+0

@think Ich unterstütze Lucas Muster vollständig, ausgenommen das unsichere. ABER ich fühle, dass sie alle mehr oder weniger Hacks sind. Ich mag ein bisschen mehr von mir, aber wir sprechen immer noch davon, ein Gemüse statt eines anderen zu wählen. An diesem Tisch ist kein Fisch oder Fleisch zu sehen. – xanatos

+0

@think es ist wichtig zu verstehen, dass nicht alles, was in C leicht gemacht werden kann, in C# leicht gemacht werden kann. Gute C-Muster sind nicht immer gute C# -Muster. Also müssen wir verstehen, akzeptieren und weitermachen, und nicht versuchen, jeden Winkel von C – xanatos

2

ich darüber eine von zwei Möglichkeiten gehen würde. Wenn Sie wirklich einen Verweis auf Ihr Objekt haben möchten, können Sie das in eine Klasse einbinden. Diese werden immer als Referenz übergeben, so dass Sie Ihre Änderung so erhalten, wie Sie es möchten, und Sie können sie auf Null setzen.

Hier ist ein Beispiel.

public class HolderObject 
{ 
    public string myStr {get; set;} 
} 
public class Program 
{ 

    public static void Main() 
    {  
     var xyz = new HolderObject() { 
      myStr = "1234" 
     }; 
     Console.WriteLine(xyz.myStr); 
     FixString(xyz); 
     Console.WriteLine(xyz.myStr); 
     FixString(); 
     Console.WriteLine(xyz.myStr); 


    } 

    private static bool FixString(HolderObject input = null) 
    { 
     if (input != null) 
      input.myStr = "test"; 
     return true; 
    } 
} 

druckt

1234 
test 

Eine andere Lösung ist Ihre Funktion zu überlasten.

bool Foo() 
{   
    // ... 
    return true; 
} 

bool Foo(ref int retVal = null) 
{ 
    // ... 
    if (retVal != null) 
    { 
     retVal = 5; 
    } 
    return Foo(); 
} 

Ich mag es wirklich nicht. Ich bin gerade mitten in der Arbeit an Code in C#, der direkt aus C++ gezogen wurde. Funktionen, die 6 oder 7 Ebenen tief verschachtelt sind und ein Objekt ändern, das als Referenz übergeben wurde. Das ist schwer zu lesen, und wenn Sie sich die Warnungen zur Codeanalyse anschauen, wird es vorschlagen, dass Sie ref-Werte nicht verwenden.

Wenn Sie können, würde ich so weit wie möglich davon abweichen Ref übergeben und den Wert zurück, der geändert wurde. Oder übergeben Sie ein Objekt, das sowohl Ihren bool als auch Ihren neuen Wert enthält.