使用 Lambda 和委托进行重构

发布于 2024-07-18 15:40:07 字数 1992 浏览 7 评论 0原文

我刚刚安装了 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

握住我的手 2024-07-25 15:40:07

听起来您正在寻找谓词函数。 无需对检查进行硬编码,而是将委托作为参数来执行检查

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

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

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

Then you can create several wrappers which just create the appropriate delegate and pass it down

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

You can even build a delegate on the fly based on arbitrary number of terminators

public bool HasData(TcpClient c, params string[] terminatorList) {
  return HasData(c, (s) => terminatorList.Where(x => s.Contains(x)).Any());
}
朱染 2024-07-25 15:40:07

一种选择是重载 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();
}

Contains() 方法扩展可以是:

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

此实现消除了每次要测试不同数量的字符串时创建新谓词的需要。

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:

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

The Contains() method extension could be:

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

This implementation eliminates the need to create a new predicate each time you have a different number of strings to test for.

等你爱我 2024-07-25 15:40:07

因为 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] 函数中添加空检查,将 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:

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

Then the calling code looks like:

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

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!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文