我有string
我需要split()
并将其值分配给两个变量。split()
是否可以返回tuple
而不是string[]
这样我就可以执行以下操作:
String myString = "hello=world"
value, id = myString.Split('=');
我正在寻找一些优雅的解决方案。
如果可以使用 C# 7 - 可以使用元组解构。如果类型具有名为 Deconstruct
的静态或扩展方法,并具有适当的签名 - 则可以解构此类型。所以你可以有这样的扩展方法:
public static class Extensions {
public static void Deconstruct<T>(this IList<T> list, out T first, out IList<T> rest) {
first = list.Count > 0 ? list[0] : default(T); // or throw
rest = list.Skip(1).ToList();
}
public static void Deconstruct<T>(this IList<T> list, out T first, out T second, out IList<T> rest) {
first = list.Count > 0 ? list[0] : default(T); // or throw
second = list.Count > 1 ? list[1] : default(T); // or throw
rest = list.Skip(2).ToList();
}
}
然后你可以用这个语法解构字符串数组(实现IList<string>
((你可能需要添加适当的using
以便上面的扩展方法可以访问(:
var line = "a=b";
var (first, second, _) = line.Split('=');
Console.WriteLine(first); // "a"
Console.WriteLine(second); // "b"
或
var line = "a=b";
var (first, (second, _)) = line.Split('=');
Console.WriteLine(first); // "a"
Console.WriteLine(second); // "b"
这非常接近您的需求。
使用上面的第一个扩展方法(解构为第一个元素和其余元素(,您可以解构为任意长度:
var (first, (second, _)) = line.Split('=');
var (first, (second, (third, _))) = line.Split('=');
var (first, rest) = line.Split('=');
// etc
仅当您想要更方便的语法来解构前 2 个值(var (first, second, rest)
而不是 var (first, (second, rest))
时,才需要第二种扩展方法
在 C# 8 中,switch 表达式可用于:
var myString = "hello=world";
var (value, id) = myString.Split('=') switch { var a => (a[0], a[1]) };
switch 表达式还允许您处理不同的数组长度:
var myString = "hello=world";
var (value, id) = myString.Split('=') switch
{
var a when a.Length == 2 => (a[0], a[1]),
_ => (null, null)
};
更新:使用C# 11列表模式也可以解构特征数组:
var (value, id) = myString.Split('=') switch
{
[var v, var i] => (v, i),
_ => default
};
不幸的是,到目前为止,这样的事情仍然只处于提案阶段:
[var value, var id] = myString.Split('='); // Does not compile!
var [value, id] = myString.Split('='); // Does not compile!
但是使用 is 表达式可以执行以下操作:
if(myString.Split('=') is [var value, var id])
{
Console.WriteLine((value, id));
}
使用 LinQ:
List<Tuple<string, string>> pairs = lines
.Select(x =>
{
string[] s = x.Split('=');
return Tuple.Create(s[0], s[1]);
})
.ToList();
在 C# 7 中,可以使用 var out
和扩展来声明和分配具有一组扩展方法的数组中的多个变量:
static class MyExtensions {
static void Assign<T>(this IList<T> items, out T v) {
v = items[0];
}
static void Assign<T>(this IList<T> items, out T v0, out T v1) {
v0 = items[0];
v1 = items[1];
}
static void Assign<T>(this IList<T> items, out T v0, out T v1, out T v2) {
v0 = items[0];
v1 = items[1];
v2 = items[2];
}
static void Assign<T>(this IList<T> items, out T v0, out T v1, out T v2, out T v3) {
v0 = items[0];
v1 = items[1];
v2 = items[2];
v3 = items[3];
}
... // And so on
}
此扩展允许您将拆分分解为单个变量,而不是元组:
Assign(myString.Split('='), var out value, var out id);
您可以使用反射动态创建元组,这将为您提供可变数量的元素的元组。
试试下面的代码片段,
static void Main(string[] args)
{
var tupple = GetTuple<string>("hello=world".Split('='));
}
public static object GetTuple<T>(params T[] values)
{
Type genericType = Type.GetType("System.Tuple`" + values.Length);
Type[] typeArgs = values.Select(_ => typeof(T)).ToArray();
Type specificType = genericType.MakeGenericType(typeArgs);
object[] constructorArguments = values.Cast<object>().ToArray();
return Activator.CreateInstance(specificType, constructorArguments);
}
以下是我最终希望对您有所帮助的内容:
static void Main()
{
var a = new List<string> {
"ID = Value",
"id=value",
"id = value"
};
var values = new List<string>();
var ids = new List<string>();
for (int i = 0; i < a.Count; i++)
{
(string value, string id) = SplitText(a[i]);
values.Add(value);
ids.Add(id);
}
Console.WriteLine($"Values -> {string.Join(", ", values)}, ID's -> {string.Join(", ", ids)}");
}
private static (string, string) SplitText(string inputText)
{
var tokens = inputText.Split(new[] { ' ', '=' }, StringSplitOptions.RemoveEmptyEntries);
return (tokens[0], tokens[1]);
}