C#:拆分字符串并将结果分配给多个字符串变量

我有一个字符串,其中有几个字段由特定字符分隔,如下所示:

A,B,C

我想在逗号中拆分字符串并将每个结果字段分配给它自己的字符串变量。 在Perl中我可以像这样优雅地做到这一点:

my ($varA, $varB, $varC) = split (/,/, $string); 

在C#中实现相同结果的最简单,最优雅的方法是什么?

我知道我可以分成一个数组:

 string[] results = string.Split(','); 

但后来我必须通过他们的索引访问字段,例如结果[2]。 这是难以阅读和容易出错的 – 考虑没有3个但是30个字段。 出于这个原因,我更喜欢将每个字段值放在自己的命名变量中。

我同意。 隐藏在Adapter类中的拆分似乎是一种很好的方法,并且很好地传达了您的意图:

 public class MySplitter { public MySplitter(string split) { var results = string.Split(','); NamedPartA = results[0]; NamedpartB = results[1]; } public string NamedPartA { get; private set; } public string NamedPartB { get; private set; } } 

您可以使用元组(在.Net 4中添加)。 MSDN中的元组

这个:

 public class MySplitter { public MySplitter(string split) { var results = split.Split(','); NamedPartA = results[0]; NamedpartB = results[1]; } public string NamedPartA { get; private set; } public string NamedPartB { get; private set; } } 

可以用这样的东西来实现:

 public Tuple SplitIntoVars(string toSplit) { string[] split = toSplit.Split(','); return Tuple.Create(split[0],split[1]); } 

使用元组你可以使用:

 var x = SplitIntoVars(arr); // you can access the items like this: x.Item1 or x.Item2 (and x.Item3 etc.) 

您还可以使用Tuple等创建元Tuple

另外……我真的不喜欢参数,所以你模拟使用元组返回多个值(显然,也有不同的类型)。 这个:

 public void SplitIntoVariables(string input, out a, out b, out c) { string pieces[] = input.Split(','); a = pieces[0]; b = pieces[1]; c = pieces[2]; } 

变成这样:

 public Tuple SplitIntoVariables(string[] input) { string pieces[] = input.Split(','); return Tuple.Create(pieces[0],pieces[1],pieces[2]); } 

其他(更富有想象力)的选项可能是创建一个包含你的值的ExpandoObject(动态)(类似于ASP.NET MVC中的ViewBag)

谁也无法抗拒一些Linq疯狂!

 string names = "Joe,Bob,Lucy"; var myVars = names.Split(',').Select((x, index) => Tuple.Create(index,x)).ToDictionary(x => "var" + x.Item1, y => y.Item2); Debug.WriteLine(myVars["var0"]); 

不是一线解决方案。 但是,带有额外out参数的扩展方法怎么样?

 public static IEnumerable Unpack(this IEnumerable source, out T target) { target = source.First(); return source.Skip(1); } 

然后,您可以使用这样的方法。

 string values = "aaa,bbb,ccc"; string x, y, z; values.Split(',') .Unpack(out x) .Unpack(out y) .Unpack(out z); 

请注意, Unpack方法枚举序列两次。 所以,我只有在IEnumerable对象中的数据是可重复的时才使用它。

我不关心检查方法的性能,因为我认为通常我们不会解压缩大型数组。

当然,您可以使用ref修饰符而不是out ,并且用法会有所不同。

我推荐一本字典。

 List names = new List (){"varA","varB","varC"}; Dictionary map = new Dictionary(); string[] results = myLongString.Split(','); for (int i = 0; i < results.Length; i++) map.Add(names[i], results[i]); 

@pnvn对Unpack模式有一个好主意,但可以改进它在一次传递中迭代枚举,提供超过可枚举末尾的默认值,并以可预测的方式处理任何类型或大小的可枚举。

以下是使用C#7 out variablesfunction的示例。

 "A,B,C".Split(',') .Unpack(out string varA) .Unpack(out string varB); 

这需要两个扩展方法,一个用于启动IEnumerable,另一个用于每个后续调用的IEnumerator。

 public static IEnumerator Unpack(this IEnumerable source, out T item) { var enumerator = source.GetEnumerator(); if (enumerator.MoveNext()) { item = enumerator.Current; return enumerator; } item = default(T); return null; } public static IEnumerator Unpack(this IEnumerator enumerator, out T item) { if (enumerator != null && enumerator.MoveNext()) { item = enumerator.Current; return enumerator; } item = default(T); return null; } 

在C#中没有内置的方法可以像在Perl中那样进行多重赋值; 但是,有多种解决方案可以通过正常路径将数据输入每个变量。

我无法抗拒加入荒谬:)请不要使用这个“解决方案”,至少不是原样。

 static class StringExtensions { private static readonly Func> GetSetter = (o1, n) => (o2, v) => o1.GetType().GetProperty(n).SetValue(o2, v, null); public static T AssignFromCSV(this string csv, T obj, string[] propertyNames) { var a = csv.Split(new[] {','}); for (var i = 0 ; i < propertyNames.Length; i++) { GetSetter(obj, propertyNames[i])(obj, a[i]); } return obj ; } } class TargetClass { public string A { get; set; } public string B { get; set; } public string C { get; set; } } 

用法:

 var target = "1,2,3".AssignFromCSV(new TargetClass(), new[] {"A", "B", "C"}) ;