如何在函数式编程中使用StringBuilder?

问题描述

我最近在阅读有关函数式编程的文章。而且我最常说的是它带来了很多好处,但是我有一些性能方面的顾虑,例如在渲染非常大的字符串(例如在html页面中连接很多字符串)时。 通常我会使用String builder。但是在遵循功能性编程范例的同时我无法使用它。

效果欠佳的代码
如您所见,ToListItemToUl是纯函数

    class Program
    {
        static string ToListItem(string s)
        {
            return "<li>" + s + "</li>";
        }
        static string ToUl(string[] items)
        {
            return "<ul>" + String.Join("",items.Select(x => ToListItem(x))) + "</ul>";
        }

        static void Main(string[] args)
        {
            string[] items = new string[]
            {
               "Apple","Orange","Banana"
            };

            string htmlUl = ToUl(items);
            Console.WriteLine(htmlUl);

        }
    }

快捷代码
但是您可以看到ToListItemToUl不再是纯函数,我无法提供在纯函数中使用StringBuilder解决方

    class Program
    {
        static void ToListItem(string s,StringBuilder sb)
        {
            sb.Append("<li>" + s + "</li>");
        }
        static void ToUl(string[] items,StringBuilder sb)
        {
            sb.Append("<ul>");

            foreach (var item in items)
                ToListItem(item,sb);

            sb.Append("</ul>");
        }

        static void Main(string[] args)
        {
            string[] items = new string[]
            {
               "Apple","Banana"
            };

            StringBuilder sb = new StringBuilder();

            ToUl(items,sb);
            Console.WriteLine(sb.ToString());

        }
    }

所以我的问题是:

是否可以通过功能编程方式使用StringBuilder?怎么样?否则,还有什么替代的性能解决方案?

更新1 我列举了一些例子。此处的性能无关紧要,但是随着列表的线性增长,性能差距将呈指数增长。

解决方法

这不能完全解决上述情况,但是它提供了一个基线,您可以在此基线上使用页眉和页脚参数构建一些内容。

using System;
using System.Collections.Generic;
using System.Text;

public static class FunctionalStringBuilder
{
    public static string BuildString<T>(this IEnumerable<T> enumerable,Func<T,string> response)
    {
        var builder = new StringBuilder();

        foreach (var item in enumerable)
        {
            builder.Append(response(item));
        }

        return builder.ToString();
    }
}

您可以像这样使用它:

    var list = new List<Employee>
    {
        AutoFaker.Generate<Employee>(),AutoFaker.Generate<Employee>(),AutoFaker.Generate<Employee>()
    };
    var result = list.BuildString(
                    e => $"Employee Id: {e.Id},Name: {e.Name},DateOfBirth: {e.DateOfBirth}\n");