在静态类方法中通过引用传递参数
Posted
技术标签:
【中文标题】在静态类方法中通过引用传递参数【英文标题】:Passing arguments by reference in static class methods 【发布时间】:2021-12-19 09:26:12 【问题描述】:我收到错误“属性或索引器可能不会作为输出或引用参数传递” 我的任务是将冒泡排序实现为静态类,如果我将其设为非静态,它就可以正常工作。
public static class BubleSort
public static void Sort(List<int> arr)
for (int i = 0; i < arr.Count-1; i++)
var flag = true;
for (int j = 0; j < arr.Count-i-1; j++)
if (arr[j] > arr[j + 1])
Swap(ref arr[j],ref arr[j + 1]);
flag = false;
if (flag)
break;
private static void Swap(ref int v1,ref int v2)
int temp = v1;
v1 = v2;
v2 = temp;
【问题讨论】:
(arr[j], arr[j + 1]) = (arr[j + 1], arr[j]);
arr[j]
是一个索引器(示例)。错误信息是正确的。您断言使其成为非静态会导致其工作是错误的:see here。
【参考方案1】:
由于编译器所说的原因,你不能做你想做的事......但是你可以只使用 的 reference列表
private static void Swap(IList<int> list, int i)
int temp = list[i];
list[i] = list[i+1];
list[i+1] = temp;
或使用 元组解构的 1 班轮
if (arr[j] > arr[j + 1])
(arr[j], arr[j + 1]) = (arr[j + 1], arr[j]);
flag = false;
那么,我听到你问哪个更快?让我们进行基准测试....
基准测试
BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22000
AMD Ryzen 9 3900X, 1 CPU, 24 logical and 12 physical cores
.NET SDK=6.0.100-rc.2.21505.57
[Host] : .NET 5.0.11 (5.0.1121.47308), X64 RyuJIT [AttachedDebugger]
.NET 5.0 : .NET 5.0.11 (5.0.1121.47308), X64 RyuJIT
Job=.NET 5.0 Runtime=.NET 5.0
结果
Method | Mean | Error | StdDev |
---|---|---|---|
Tuple | 3.555 ms | 0.0170 ms | 0.0159 ms |
Classic | 3.542 ms | 0.0075 ms | 0.0062 ms |
测试代码
[SimpleJob(RuntimeMoniker.Net50)]
public class Test
private List<int> data;
[GlobalSetup]
public void Setup()
var r = new Random(42);
data = Enumerable.Range(0,1000000).Select(x => r.Next()).ToList();
[Benchmark]
public void Tuple()
for (int i = 0; i < data.Count-1; i++)
Swap1(data, i);
[Benchmark]
public void Classic()
for (int i = 0; i < data.Count-1; i++)
Swap1(data, i);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void Swap1(List<int> l, int i)
(l[i], l[i+1]) = (l[i+1], l[i]);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void Swap2(List<int> l, int i)
int temp = l[i];
l[i] = l[i+1];
l[i+1] = temp;
总结
这个基准测试完全是浪费时间,最好不要担心其他事情。
【讨论】:
【参考方案2】:Indexer access returns temporary value. 'ref' argument must be an assignable variable, field or an array element
您不能从列表中发送引用,因为对特定索引元素的访问是通过索引器完成的。 see more about indexers
相反,您可以使用 ref 从数组 int[]
发送引用,因为它不是使用索引器,而是直接引用。
如果你还想用list,你可以使用C#特性来交换:
(arr[j],arr[j + 1]) = (arr[j + 1], arr[j]);
而不是Swap
方法
你的代码会变成
public static class BubleSort
public static void Sort(List<int> arr)
for (int i = 0; i < arr.Count-1; i++)
var flag = true;
for (int j = 0; j < arr.Count-i-1; j++)
if (arr[j] > arr[j + 1])
(arr[j],arr[j + 1]) = (arr[j + 1], arr[j]);
flag = false;
if (flag)
break;
【讨论】:
【参考方案3】:语言中有一个返回参考的功能。但这是为数组索引器实现的,而不是列表索引器,因为可以重新分配列表。因此,如果您将 arr
更改为数组,我希望您的示例代码能够正常工作。看这个最小的例子:
public void SwapTest()
var arr = new [] 1, 2;
Swap( ref arr[0], ref arr[1]);
public static void Swap(ref int a, ref int b)
var tmp = a;
a = b;
b = tmp;
但是,对于大多数实际应用,我建议使用@TheGeneral 发布的解决方案之一。 ref 返回有点不寻常,可能不是所有程序员都熟悉。
【讨论】:
【参考方案4】:在这种情况下 arr[j] 被认为是一个属性,因为它需要读取列表中的一个字段。属性不是变量。它们是方法,不能传递给 ref 参数。
如果你想这样做,你需要将数组属性传递给一个临时变量。
示例:
if (arr[j] > arr[j + 1])
int tempJ = arr[j];
int tempJ2 = arr[j + 1];
Swap(ref tempJ, ref tempJ2);
arr[j] = tempJ;
arr[j + 1] = tempJ2;
flag = false;
【讨论】:
以上是关于在静态类方法中通过引用传递参数的主要内容,如果未能解决你的问题,请参考以下文章