2009-05-01 67 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表达式!