闽公网安备 35020302035485号
ParamsArrayMethod(1, 2, 3);
ParamsListMethod(1, 2, 3);
ParamsEnumerableMethod(1, 2, 3);
ParamsSpanMethod(1, 2, 3);
ParamsReadOnlySpanMethod(1, 2, 3);
void ParamsReadOnlySpanMethod(params ReadOnlySpan<int> collection)
{
foreach (var item in collection)
{
Console.WriteLine(item);
}
}
void ParamsSpanMethod(params Span<int> collection)
{
foreach (var item in collection)
{
Console.WriteLine(item);
}
}
void ParamsListMethod(params List<int> list)
{
foreach (var item in list)
{
Console.WriteLine(item);
}
}
void ParamsEnumerableMethod(params IEnumerable<int> array)
{
foreach (var item in array)
{
Console.WriteLine(item);
}
}
void ParamsArrayMethod(params int[] array)
{
foreach (var item in array)
{
Console.WriteLine(item);
}
}
这些在 C# 13 中都是完全合法的使用。在 C# 12 collection expression 的介绍中我们提到过,我们可以实现自定义的集合也支持 collection expression。我们来试试,params 是不是支持我们自定义的集合呢,自定义的集合定义如下:[CollectionBuilder(typeof(CustomCollectionBuilder), nameof(CustomCollectionBuilder.CreateNumber))]
file sealed class CustomNumberCollection : IEnumerable<int>
{
public required int[] Numbers { get; init; }
public IEnumerator<int> GetEnumerator()
{
return (IEnumerator<int>)Numbers.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return Numbers.GetEnumerator();
}
}
file static class CustomCollectionBuilder
{
public static CustomNumberCollection CreateNumber(ReadOnlySpan<int> elements)
{
return new CustomNumberCollection()
{
Numbers = elements.ToArray()
};
}
}
params 使用示例如下:void ParamsCustomCollectionMethod(params CustomCollection<int> collection)
{
foreach (var item in collection)
{
Console.WriteLine(item);
}
}
ParamsCustomCollectionMethod(1, 2, 3);
dotnet run
public static void OverloadTest(params int[] array)
{
Console.WriteLine("Executing in Array method");
}
public static void OverloadTest(params ReadOnlySpan<int> span)
{
Console.WriteLine("Executing in Span method");
}
首先我们来对比一下 ReadOnlySpan 和数组ParamsCollectionTest.OverloadTest(1, 2, 3);
ParamsCollectionTest.OverloadTest([1, 2, 3]);
ParamsCollectionTest.OverloadTest(new[] { 1, 2, 3 });
可以先猜测一下输出结果会是什么呢?
[OverloadResolutionPriority(1)]
public static void OverloadTest2(params int[] array)
{
Console.WriteLine("Executing in Array method");
}
public static void OverloadTest2(params ReadOnlySpan<int> span)
{
Console.WriteLine("Executing in Span method");
}
实际输出结果和之前还是一样的,这个 attribute 目前还不工作(现在使用的是 .NET 9 Preview 5),编译器目前还未支持:https://github.com/dotnet/roslyn/issues/74067public static void OverloadTest3(params IEnumerable<int> values)
{
Console.WriteLine("Executing in IEnumerable method");
}
public static void OverloadTest3(params int[] array)
{
Console.WriteLine("Executing in Array method");
}
public static void OverloadTest3(params List<int> values)
{
Console.WriteLine("Executing in List method");
}
测试代码:ParamsCollectionTest.OverloadTest3(1, 2, 3); ParamsCollectionTest.OverloadTest3([1, 2, 3]); ParamsCollectionTest.OverloadTest3(Enumerable.Range(1, 3));

public static void OverloadTest3(params ICollection<int> values)
{
Console.WriteLine("Executing in ICollection method");
}
最后来猜一下下面这样的重载输出结果会是什么呢?public static void OverloadTest4(params IEnumerable<int> values)
{
Console.WriteLine("Executing in IEnumerable method");
}
public static void OverloadTest4(params ICollection<int> values)
{
Console.WriteLine("Executing in ICollection method");
}
public static void OverloadTest4(params IList<int> values)
{
Console.WriteLine("Executing in IList method");
}
ParamsCollectionTest.OverloadTest4(1, 2, 3);
ParamsCollectionTest.OverloadTest4([1, 2, 3]);
ParamsCollectionTest.OverloadTest4(Enumerable.Range(1, 3));
Span 的优先级比较高总体上来说会有一些优化,比如不需要创建数组从而避免内存分配,减少 GC 的压力,那具体会有多少差异呢,我们可以跑个简单的 benchmark 试一下[SimpleJob]
[MemoryDiagnoser]
public class ParamsCollectionTest
{
[Benchmark(Baseline = true)]
public int ParamsSpanMethod()
{
return ParamsOverloadMethod(1, 2, 3);
}
[Benchmark]
public int ParamsArrayMethod()
{
return ParamsOverloadMethod(new[] { 1, 2, 3 });
}
private int ParamsOverloadMethod(params ReadOnlySpan<int> span)
{
return span.Length;
}
private int ParamsOverloadMethod(params int[] array)
{
return array.Length;
}
}
benchmark result: