Frage

Ich habe gerade VS2008 installiert und bin auf ein Problem gestoßen, das sicher mit Lambda oder Delegierten (oder einer Kombination!) Gelöst werden kann.

    private string ReadData(TcpClient s, string terminator)
    {
        // Reads a byte steam into a string builder until either data is unavailable or the terminator has not been reached
        var sb = new StringBuilder();
        do
        {
            var numBytesRead = s.GetStream().Read(byteBuff, 0, byteBuff.Length);
            sb.AppendFormat("{0}", Encoding.ASCII.GetString(byteBuff, 0, numBytesRead));
        } while (s.GetStream().DataAvailable && !sb.ToString().Contains(terminator));

        return sb.ToString();
    }

Das Problem ist, dass ich manchmal überprüfen muss, ob die Zeichenfolge eine von zwei verschiedenen Werten enthält. Manchmal muss ich es möglicherweise auf drei Werte überprüfen.

Ich schlage also vor, sich zu ändern "!

Ich könnte meine verschiedenen Funktionen schreiben wie:

private bool compare1(string s, string t) {
    return s.contains(t)
}

private bool compare2(string s, string t1, string t2) {
    return (s.compare(t1) or s.compare(t2)
}

// etc...

Wenn ich dann mit 3 verschiedenen Werten vergleichen möchte, erstellen Sie einen Delegierten mit einer dieser Funktionen und übergeben Sie diese an die ReadData () -Methode.

Ich bin sehr ahnungslos, wenn es um Delegierte geht, und ich bin mir nicht sicher, ob dies der richtige Ort für ein Lambda erscheint, aber mir sagt mir etwas.

Der aufrufende Code lautet:

            // Enter username .
        if (HasData(s,"login:"))
            SendData(s, switchUser + TelnetHelper.CRLF);

HasData ist identisch mit Readdata, gibt aber einen Bool anstelle einer String zurück (die ich auch mit einigen Tricks in eine Methode berücksichtigen würde - aber das ist eine sekundäre Frage - können Sie dies jedoch gerne beantworten.

Nur als Referenz:

     private bool HasData(TcpClient s, string terminator)
    {
        // Reads a byte steam into a string builder until either data is unavailable or the terminator has not been reached
        var sb = new StringBuilder();
        do
        {
            var numBytesRead = s.GetStream().Read(byteBuff, 0, byteBuff.Length);
            sb.AppendFormat("{0}", Encoding.ASCII.GetString(byteBuff, 0, numBytesRead));
        } while (s.GetStream().DataAvailable && !sb.ToString().Contains(terminator));

        return sb.ToString().Contains(terminator);
    }
War es hilfreich?

Lösung

Es hört sich so an, als würden Sie nach einer Prädikatfunktion suchen. Nehmen Sie anstatt die Prüfung zu kodieren, anstatt die Prüfung zu kodieren

    private string ReadData(TcpClient s, Func<string,bool> predicate)
    {
        // Reads a byte steam into a string builder until either data is unavailable or the terminator has not been reached
        var sb = new StringBuilder();
        do
        {
            var numBytesRead = s.GetStream().Read(byteBuff, 0, byteBuff.Length);
            sb.AppendFormat("{0}", Encoding.ASCII.GetString(byteBuff, 0, numBytesRead));
        } while (s.GetStream().DataAvailable && !predicate(sb));

        return sb.ToString();
    }

Dann können Sie mehrere Wrapper erstellen, die einfach den entsprechenden Delegierten erstellen und sie abgeben

public bool HasData(TcpClient c, string terminator) {
  return HasData(c, (s) => s.Contains(terminator));
}

public bool HasData(TcpClient c, string t1, string t2) {
  return HasData(c, (s) => s.Contains(t1) || s.Contains(t2));
}

Sie können sogar einen Delegierten basierend auf der willkürlichen Anzahl von Terminatoren erstellen

public bool HasData(TcpClient c, params string[] terminatorList) {
  return HasData(c, (s) => terminatorList.Where(x => s.Contains(x)).Any());
}

Andere Tipps

Eine Option besteht darin, die ReadData () -Methode zu überladen, um ein String -Array mit den Werten zu erhalten, auf die Sie prüfen. Mit an ein Erweiterungsmethode, Sie könnten ausdehnen (), um ein String -Array zu nehmen.

Ihre Readdata () -Methode könnte sein:

private string ReadData(TcpClient s, string[] terminators) {
    // Reads a byte steam into a string builder until either data is unavailable or the terminator has not been reached
    var sb = new StringBuilder();
    do
    {
        var numBytesRead = s.GetStream().Read(byteBuff, 0, byteBuff.Length);
        sb.AppendFormat("{0}", Encoding.ASCII.GetString(byteBuff, 0, numBytesRead));
    } while (s.GetStream().DataAvailable && !sb.ToString().Contains(terminators));

    return sb.ToString();
}

Die Methodenerweiterung containes () könnte sein:

public static bool Contains ( this String str , String[] testValues )
{
    foreach ( var value in testValues )
    {
        if ( str.Contains( value ) )
            return true;
    }
    return false;
}

Diese Implementierung beseitigt die Notwendigkeit, jedes Mal ein neues Prädikat zu erstellen, wenn Sie eine andere Anzahl von Strings zum Testen haben.

Da die Syntax der Lambdas mir (und dem Rest meines Teams) etwas fremd ist, habe ich mit einer etwas anderen Lösung gekommen. Ich konnte die Syntax von .All () nicht herausfinden, wenn ich aus der obigen Funktion .any () modifiziert wurde.

Ich brauchte auch eine .all () -Funktion, um sicherzustellen, dass alle Terminatoren in der Liste gefunden wurden. Also ging ich mit so etwas wie folgt:

delegate bool Predicate (string s, params [] string terminators);

bool HasAll(string s, params string [] terminators) {
    foreach (var t in terminators) {
       if (!s.contains(t)) return false;
    }
    return true;
}

bool HasAny(string s, params string [] terminators) {
    foreach (var t in terminators) {
        if (s.contains(t)) return true;
    }
    return false;
}
// Just looking now, I could also pass in a bool to switch between the two and remove one of these functions. But this is fairly clear


string ReadData(TcpClient sock, Function predicate, params [] string terminators) {
    var sb = new StringBuilder();
    do
    {  
        var numBytesRead = s.GetStream().Read(byteBuff, 0, byteBuff.Length);
        sb.AppendFormat("{0}", Encoding.ASCII.GetString(byteBuff, 0, numBytesRead));
    } while (s.GetStream().DataAvailable && !predicate(sb.ToString(), terminators);

    return sb.ToString();
}

Dann sieht der Anrufcode aus:

private void someFunc() 
{
    Predicate any = new Predicate(HasAny);
    Predicate all = new Predicate(HasAll);
    String response;

    // Check all strings exist
    response = ReadData(this.sock, all, "(", ")", "->")
    if (all(response, "(", ")", "->")
        SendData(this.sock, ...);

    // Check any string exists
    response = ReadData(this.sock, any, "Hi", "Hey", "Hello");
    if (any(response, "Hi", "Hey", "Hello"))
       SendData(this.sock, ...);
}

Ich werde wahrscheinlich Nullprüfungen in die Funktionen [alle | alle] Funktionen hinzufügen, das DO ... während eine Weile umkehren und einfach die Antwort überprüfen! = Null, anstatt die Params zu duplizieren. Diese Lösungen passt zu allen meinen Anwendungsfällen und ist meiner Meinung nach ziemlich menschlich lesbar. Solange ich die kleinen Änderungen vornehme, die ich genau oben erwähnt habe.

Das Ganze zeigt für mich mein Bedürfnis, Lambda -Ausdrücke zu lernen!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top