我刚刚安装了VS2008并遇到了一个问题,我确信可以用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(terminator)”更改为传递给方法的函数。
我可以编写不同的功能,例如:
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相同,但是返回一个bool而不是一个字符串(我也想用一些技巧将其分解为一个方法 - 但这是一个次要问题 - 尽管可以自由地回答这个问题。
仅供参考:
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);
}
答案 0 :(得分:4)
听起来你正在寻找一个谓词函数。不要对支票进行硬编码,而是将代理作为参数,而不是检查
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());
}
答案 1 :(得分: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;
}
每次有不同数量的字符串需要测试时,此实现消除了创建新谓词的需要。
答案 2 :(得分:0)
因为lambdas的语法对我自己(以及我的团队的其他成员)来说有点陌生,所以我最终得到了一个稍微不同的解决方案。从上面的.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, ...);
}
我可能会将空检查添加到Has [Any | All]函数中,将do..while转换为while,然后检查响应!= null而不是复制参数。这个解决方案适合我所有的用例,我认为它具有相当的人性化。只要我做了上面提到的小改动。
这一切都让我想到了学习lambda表达式的必要性!