2009-05-01 40 views
1

我剛剛安裝了VS2008,遇到了一個問題,我肯定可以用lambda或代表(或組合!)解決問題。用Lambda和代表重構

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(); 
    } 

問題是,有時我需要檢查字符串是否包含兩個不同的值。有時我可能需要檢查它的三個值。

因此,我建議將「!sb.ToString()。Contains(終止符)」更改爲傳遞給該方法的函數。

我可以寫我的不同的功能,如:

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... 

然後,當我想用​​3個不同的值進行比較,創建委託給這些函數之一,然後傳遞到READDATA()方法。

對於代表們,我非常無能,而且我不確定這是不是一個lambda的正確位置,但有些東西告訴我它是。

調用代碼是這樣的:

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

HasData是相同的READDATA,但返回一個布爾值,而不是一個字符串(這也是我想使用一些詭計分解出成一個方法 - 但是這次要的問題 - 隨時接聽,雖然

僅供參考:

 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); 
    } 

回答

4

這聽起來像你正在尋找一個謂語函數,而不是公頃。 RD編碼的檢查,採取委託作爲參數不是可以做檢查

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(); 
    } 

然後,您可以創建多個包裝剛剛創建相應的委託和它向下傳遞

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)); 
} 

你甚至可以建立基於任意數量的終止符的實時代理

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

儘管謂詞(sb)需要更改爲謂詞(sb.ToString()) - 不會讓我編輯。 – 2009-05-01 03:08:30

1

一個選項是重載ReadData()方法以獲取包含您所在的值的字符串數組檢查。使用extension method,可以擴展Contains()以獲取字符串數組。

你READDATA()方法可以是:

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(); 
} 

的contains()方法的擴展可能是:

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

此實現,無需在每次有一次創建一個新的謂詞不同數量的字符串進行測試。

0

因爲lambda的語法對我自己(以及我的團隊的其他成員)來說有點陌生,所以我最終選擇了一個稍微不同的解決方案。從上面的.Any()函數修改時,我無法弄清.All()的語法。

我需要一個。All()函數也可以確保找到列表中的所有終止符。所以我結束了類似去以下:

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(); 
} 

然後調用代碼如下所示:

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, ...); 
} 

我可能會添加null檢查到有[任何|全部]功能,倒車do .. while有一段時間,只是檢查響應!= null而不是複製params。這個解決方案適合我所有的用例,並且我認爲它是相當人性化的。只要我做出上面提到的小改動。

這整件事對我來說突出了我需要學習lambda表達式!