通过引用传递到 C# 中的第 n 个元素

Passing by reference to n-th element in C#

在 C 中,如果我们有一个数组,我们可以通过引用将它传递给一个函数。我们还可以使用简单的 (n-1) 相加来传递从数组的第 n 个元素开始的引用,如下所示:

char *strArr[5];
char *str1 = "I want that!\n";
char *str2 = "I want this!\n";
char *str3 = "I want those!\n";
char *str4 = "I want these!\n";
char *str5 = "I want them!\n";
strArr[0] = str1;
strArr[1] = str2;
strArr[2] = str3;
strArr[3] = str4;
strArr[4] = str5;
printPartially(strArr + 1, 4); //we can pass like this to start printing from 2nd element

....

void printPartially(char** strArrPart, char size){
int i;
for (i = 0; i < size; ++i)
    printf(strArrPart[i]);
}

导致这些:

I want this!
I want those!
I want these!
I want them!

Process returned 0 (0x0)   execution time : 0.006 s
Press any key to continue.

在 C# 中,我们还可以通过 ref(或 out)传递对 object 的引用。该对象包括数组,它是 whole 数组(或者至少,我认为它是这样工作的)。但是我们如何通过引用传递数组的第 n 个元素,使得在函数内部,只有 string[] 其元素比原始 string[] 少一个而不需要创建新数组吗?

我们必须使用unsafe吗?我正在寻找没有 unsafe

的解决方案(如果可能的话)

编辑:

我知道我们可以在没有 ref 关键字的情况下在 C# 中传递 Array。当我们谈论 Array 时,提及 ref 可能听起来很误导我的问题。为什么我把 ref 放在那里,我应该这样说:是否可以使用 ref 关键字,比如说,将引用传递给数组的第 n 个元素除了传递对任何 object 的引用(不提及第 n 元素或类似的东西)之外,C 所做的一样多吗?对于我问题的措辞造成的任何误解,我深表歉意。

"safe" 方法是传递一个 ArraySegment 结构。

您当然可以使用不安全的 c# 传递指向字符的指针,但是您需要担心缓冲区溢出。

顺便说一句,C# 中的数组(通常)分配在堆上,因此正常传递它(没有引用)并不意味着复制数组 - 它仍然是传递的引用(只是一个新引用)。

编辑:

您将无法像在 安全 代码中使用 C 那样执行此操作。

C# 数组(即 string[])派生自抽象类型 Array。 它不仅仅是一个简单的内存块,因为它在 C.

所以您不能发送其中一个元素的引用并从那里开始迭代。


但是有一些解决方案当然会给你相同的味道(没有 unsafe):

喜欢:

  • 如@Chris 所述,您可以使用 ArraySegment<T>.
  • 由于 Array 也是一个 IEnumerable<T>,您可以使用 .Skip 并发送返回值。 (但这会给你一个 IEnumerable<T> 而不是 Array)。但它会让你迭代。
  • 等...

你的困惑很常见。要点是要意识到 "reference types" 和 "passing by reference"(参考键盘)是完全独立的。在这种特定情况下,由于 string[] 是引用类型(所有数组也是),这意味着当您传递对象时不会复制该对象,因此您总是引用同一个对象。

C# 代码的修改版本:

string[] strArr = new string[5];
strArr[0] = "I want that!\n";
strArr[1] = "I want this!\n";
strArr[2] = "I want those!\n";
strArr[3] = "I want these!\n";
strArr[4] = "I want them!\n";
printPartially(strArr.Skip(1).Take(4).ToArray());

void printPartially(string[] strArr)
{
    foreach (string str in strArr)
    {
        Console.WriteLine(str);
    }
}

如果该方法只应从数组中读取,您可以使用 linq:

string[] strings = {"str1", "str2", "str3", ...."str10"};
print(strings.Skip(1).Take(4).ToArray());

问题很旧,但也许答案对某人有用。 从 C# 7.2 开始,在这种情况下可以使用更多类型,例如。 Span or Memory.
他们完全允许您在问题中提到的事情(以及更多)。
Here's great article about them

目前,如果你想使用它们,记得在你的项目的 .csproj 文件中添加 <LangVersion>7.2</LangVersion> 以使用 C# 7.2 特性