使用 Lambda 和委托进行重构
我刚刚安装了 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);
}
I've just installed VS2008 and have run into a problem that I'm sure can be solved with either lambda's or delegates (or a combination!).
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();
}
The problem is, sometimes I need to check if the string contains either of two different values. Sometimes I may need to check it for three values.
So what I propose, is to change " !sb.ToString().Contains(terminator)" to a function that is passed into the method.
I could write my different functions such as:
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...
Then when I want to compare with 3 different values, create a delegate to one of these functions, then pass that to the ReadData() method.
I'm very clueless when it comes to delegates, and I'm not sure if this seems like the right place for a lambda but something is telling me it is.
The calling code is this:
// Enter username .
if (HasData(s,"login:"))
SendData(s, switchUser + TelnetHelper.CRLF);
HasData is identical to ReadData, but returns a bool instead of a string (which I'd also like to factor out into one method using some trickery - but that's a secondary question - feel free to answer that though.
Just for reference:
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);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
听起来您正在寻找谓词函数。 无需对检查进行硬编码,而是将委托作为参数来执行检查
然后您可以创建多个包装器,这些包装器仅创建适当的委托并将其传递下来
您甚至可以基于任意数量的终止符动态构建委托
It sounds like you're looking for a predicate function. Instead of hard coding the check, take a delegate as a parameter than can do the check
Then you can create several wrappers which just create the appropriate delegate and pass it down
You can even build a delegate on the fly based on arbitrary number of terminators
一种选择是重载 ReadData() 方法以获取包含您要检查的值的字符串数组。 使用 扩展方法,您可以扩展 Contains() 来获取字符串数组。
您的 ReadData() 方法可以是:
Contains() 方法扩展可以是:
此实现消除了每次要测试不同数量的字符串时创建新谓词的需要。
One option would be to overload the ReadData() method to take a string array containing the values that you are checking for. Using an extension method, you could extend Contains() to take a string array.
Your ReadData() method could be:
The Contains() method extension could be:
This implementation eliminates the need to create a new predicate each time you have a different number of strings to test for.
因为 lambda 的语法对我自己(以及我团队的其他成员)来说有点陌生,所以我最终采用了稍微不同的解决方案。 当从上面的 .Any() 函数修改时,我无法弄清楚 .All() 的语法。
我还需要一个 .All() 函数,以确保找到列表中的所有终止符。 所以我最终采用了类似以下的内容:
然后调用代码如下所示:
我可能会在 Has[Any|All] 函数中添加空检查,将 do..while 反转为一段时间,然后检查响应! = null 而不是重复参数。 该解决方案适合我的所有用例,并且我认为具有相当的人类可读性。 只要我做出上面提到的小改变。
这整件事凸显了我学习 lambda 表达式的需要!
Because the syntax of the lambdas is somewhat foreign to myself (and the rest of my team) I ended up going with a slightly different solution. I couldn't figure out the syntax of .All() when modified from the .Any() function above.
I needed an .All() function as well, to ensure all the terminators in the list were found. So I ended up going with something like the following:
Then the calling code looks like:
I'll probably add null checks into the Has[Any|All] functions, reverse the do..while to a while, and just check response != null instead of duplicating the params. This solutions suits all my use cases and is fairly human readable I think. As long as I make the small changes I mentioned just above.
This whole thing highlights for me my need to learn lambda expressions though!