C# 使用Lambda'进行重构;代表和代表
我刚刚安装了VS2008,遇到了一个问题,我确信可以通过lambda或委托(或组合!)解决 问题是,有时我需要检查字符串是否包含两个不同的值。有时我可能需要检查它的三个值 因此,我建议将“!sb.ToString().Contains(terminator)”更改为传递到方法中的函数 我可以编写不同的函数,例如:C# 使用Lambda'进行重构;代表和代表,c#,.net,refactoring,delegates,lambda,C#,.net,Refactoring,Delegates,Lambda,我刚刚安装了VS2008,遇到了一个问题,我确信可以通过lambda或委托(或组合!)解决 问题是,有时我需要检查字符串是否包含两个不同的值。有时我可能需要检查它的三个值 因此,我建议将“!sb.ToString().Contains(terminator)”更改为传递到方法中的函数 我可以编写不同的函数,例如: private bool compare1(string s, string t) { return s.contains(t) } private bool compare
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);
}
听起来你在寻找一个谓词函数。与其对检查进行硬编码,不如将委托作为一个参数来执行检查
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, params string[] terminatorList) {
return HasData(c, (s) => terminatorList.Where(x => s.Contains(x)).Any());
}
听起来你在寻找一个谓词函数。与其对检查进行硬编码,不如将委托作为一个参数来执行检查
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, params string[] terminatorList) {
return HasData(c, (s) => terminatorList.Where(x => s.Contains(x)).Any());
}
一个选项是重载ReadData()方法以获取包含要检查的值的字符串数组。使用,可以扩展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();
}
public static bool Contains ( this String str , String[] testValues )
{
foreach ( var value in testValues )
{
if ( str.Contains( value ) )
return true;
}
return false;
}
Contains()方法扩展可以是:
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();
}
public static bool Contains ( this String str , String[] testValues )
{
foreach ( var value in testValues )
{
if ( str.Contains( value ) )
return true;
}
return false;
}
此实现消除了每次有不同数量的字符串要测试时创建新谓词的需要。一个选项是重载ReadData()方法以获取包含要检查的值的字符串数组。使用,可以扩展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();
}
public static bool Contains ( this String str , String[] testValues )
{
foreach ( var value in testValues )
{
if ( str.Contains( value ) )
return true;
}
return false;
}
Contains()方法扩展可以是:
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();
}
public static bool Contains ( this String str , String[] testValues )
{
foreach ( var value in testValues )
{
if ( str.Contains( value ) )
return true;
}
return false;
}
此实现消除了每次需要测试不同数量的字符串时创建新谓词的需要。因为lambdas的语法对我自己(以及我的团队的其他成员)来说有些陌生,所以我最终使用了一个稍微不同的解决方案。我无法理解.All()的语法从上面的.Any()函数修改时 我还需要一个.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]函数中添加null检查,将do..while改为while,然后只检查response!=null,而不是复制参数。我认为这种解决方案适合我的所有用例,并且是相当容易理解的。只要我做了上面提到的小更改
但是,这一切都突出了我学习lambda表达式的必要性!因为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, ...);
}
我可能会在Has[Any | All]函数中添加null检查,将do..while改为while,然后只检查response!=null,而不是复制参数。我认为这种解决方案适合我的所有用例,并且是相当容易理解的。只要我做了上面提到的小更改
这件事让我意识到我需要学习lambda表达式!虽然谓词(sb)需要更改为谓词(sb.ToString())-不允许我编辑。语法让我有些困惑。它不应该在(x=>s.contains(x)).any()的位置,因为s是我们要检查终止符的字符串吗?@Josh,是的,你在哪里写错误。我修正了。虽然谓词(sb)需要更改为谓词(sb.ToString())-但不允许我编辑。语法让我有些困惑。它不应该是(x=>s.contains(x)).any()),因为s是我们要检查终结符的字符串吗?@Josh,是的,你在where中写的bug。我修好了。