在C#中创建逗号分隔的字符串

73

我有一个对象保存了很多值,其中一些值(而不是所有值)需要放在逗号分隔值字符串中。我的方法如下:

string csvString = o.number + "," + o.id + "," + o.whatever ....

有没有更好、更优雅的方法?


1
一般来说,使用 + 符号连接字符串被认为是效率较低的。它会创建更多需要被垃圾回收的对象。 - Phil Gan
6个回答

145
如果您将所有的值都放到一个数组中,那么您至少可以使用 string.Join
string[] myValues = new string[] { ... };
string csvString = string.Join(",", myValues);

你还可以使用 string.Join 的另一种重载,它将 params string 作为第二个参数,例如:

string csvString = string.Join(",", value1, value2, value3, ...);

1
@fearofawhackplanet - 感谢您给出理由。这样更有意义;) 当然,您有权发表自己的观点。我只是想听听它;) - Øyvind Bråthen
使用数组会更好,而且功能可以更容易地扩展。+1 - Phil Gan
4
string.Join使用可变参数数组。这意味着直接传递参数的代码将由编译器自动转换为使用数组。就开销而言,这些调用之间没有任何区别。 - Jeff Mercado
这并不是针对CSV字符串严格正确的答案。真正的CSV将根据需要转义字符串。 - jgmjgm
如果值包含逗号,该怎么办?例如,我有像test1、test2和test、test3这样的值,其中test、test3应被视为单个值。 - Nimesh khatri
显示剩余4条评论

15

另一种方法是使用来自System.Configuration命名空间/程序集的CommaDelimitedStringCollection类。它的行为类似于列表,并且具有被覆盖的ToString方法,该方法返回一个以逗号分隔的字符串。

优点-比数组更灵活。

缺点-您不能传递包含逗号的字符串。

CommaDelimitedStringCollection list = new CommaDelimitedStringCollection();

list.AddRange(new string[] { "Huey", "Dewey" });
list.Add("Louie");
//list.Add(",");

string s = list.ToString(); //Huey,Dewey,Louie

5
你可以使用 string.Join 方法来执行类似于 string.Join(",", o.Number, o.Id, o.whatever, ...) 的操作。
编辑:正如 digEmAll 所说,string.Join 比 StringBuilder 更快。它们使用 string.Join 的外部实现。
代码性能分析(当然在发布时不带调试符号):
class Program
{
    static void Main(string[] args)
    {
        Stopwatch sw = new Stopwatch();
        string r;
        int iter = 10000;

        string[] values = { "a", "b", "c", "d", "a little bit longer please", "one more time" };

        sw.Restart();
        for (int i = 0; i < iter; i++)
            r = Program.StringJoin(",", values);
        sw.Stop();
        Console.WriteLine("string.Join ({0} times): {1}ms", iter, sw.ElapsedMilliseconds);

        sw.Restart();
        for (int i = 0; i < iter; i++)
            r = Program.StringBuilderAppend(",", values);
        sw.Stop();
        Console.WriteLine("StringBuilder.Append ({0} times): {1}ms", iter, sw.ElapsedMilliseconds);
        Console.ReadLine();
    }

    static string StringJoin(string seperator, params string[] values)
    {
        return string.Join(seperator, values);
    }

    static string StringBuilderAppend(string seperator, params string[] values)
    {
        StringBuilder builder = new StringBuilder();
        builder.Append(values[0]);
        for (int i = 1; i < values.Length; i++)
        {
            builder.Append(seperator);
            builder.Append(values[i]);
        }
        return builder.ToString();
    }
}

在我的机器上,string.Join花费了2毫秒,而StringBuilder.Append则花费了5毫秒。因此有值得注意的差异。感谢digAmAll的提示。


2
string.JoinStringBuilder 一样快(如果不是稍微更快),因为它们都只分配一个字符串。 - digEmAll
普通字符串连接的问题(例如使用string1 += string2)是原始字符串string1被丢弃了(因为字符串是不可变的),而string1和string2的新总和由string1指向,如果重复执行这个操作,那么效率就不是很高。然而,正如digEmAll所指出的那样,string.Join只分配一次字符串。而不是为数组中的每个元素都分配一次。 - Øyvind Bråthen
string.Join 的一个缺点(直到 .NET 4.0)是它需要一个字符串数组,如果你只有一个通用的 IEnumerable<string>,就必须分配一个。不过,无论如何,.NET 4.0 已经解决了这个问题。 - digEmAll
你是正确的,我编辑了我的帖子。但我想知道在string.Join中调用了哪个外部方法,因为它是一种本地实现,而不在mscorlib内部? - jb_
@jb_: 实际上(我的错),我只检查了 .net 2 的 string.Join 实现,那两个重载(接受 string[])使用了一个名为 FastAllocateString 的外部方法,它可能(有时候)稍微快一些。令我惊讶的是,.net 4 引入的新的 string.Join 重载内部简单地使用了一个 StringBuilder!因此,这两种方法没有区别,我的建议是为了简单起见(和“不要重复造轮子”的原则),使用 string.Join() - digEmAll
1
@digEmAll:但基础仍然是正确的,所以没有需要找借口的必要 :-)。string.Join(string, string[])和string.Join(string, string[], int, int)重载仍然使用FastAllocateString,因此可能比string.Join的其他重载更快。但我同意使用string.Join比实现自己的Join-Logic与StringBuilder更可取。 - jb_

4
如果您使用的是.NET 4,您可以使用`string.Join`的重载函数,如果您有一个List对象,它还可以接受IEnumerable类型的参数:
string.Join(", ", strings);

1
你可以重写对象的ToString()方法:
public override string ToString ()
{
    return string.Format ("{0},{1},{2}", this.number, this.id, this.whatever);
}

这只有在他确切地知道要放入字符串中的元素数量时才有用。string.Join 可能更适合。 - Øyvind Bråthen
是的,但由于他想创建一个csv文件,元素很可能每次都是相同的。我不知道,这是个人喜好问题。 - Dimitris Tavlikos
我从问题中推断出他总是想要相同的字段,因此他肯定知道元素的数量。这个答案没有任何问题,尽管我不太喜欢在这里重写ToString,因为它可能不够通用。无论如何,我给你点赞。 - fearofawhackplanet
@fearofawhackplanet - 没什么问题。只是个人喜好的问题 ;) - Øyvind Bråthen

0

是的,有多种方法可以做到这一点。

如果您有字符串的List/Array,那么您可以采用它;

string[] myStrings = new string[] { "Hi", "stackoverflow", };
string csvString = string.Join(",", myStrings);  // csvString :: Hi,stackoverflow

如果你有多个字符串,那么你可以采用它;

string st1 = "Hi";
string st2 = "stackoverflow";
string st3 = "team";
string csvString = string.Join(",", st1, st2, st3);  // csvString :: Hi,stackoverflow,team

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接