如何通过引用传递c#结构体

本文关键字:结构体 何通过 引用 | 更新日期: 2023-09-27 18:14:03

在我的c#应用程序中,我在回调/委托中收到一个指向c++结构体的指针。我不确定class是否可以做到这一点,但只是将c++指针转换为适当的c#结构体就可以了,所以我使用c#结构体来存储数据。

现在我想传递一个引用到结构体,以便进一步处理。

  • 我不能使用class,因为它可能不会"映射"。
  • 我不想复制结构体以获得更好的延迟。

我该怎么做呢?


这个例子说明了struct是按值传递的,而不是按引用传递的:

using System;
namespace TestStruct
{
    struct s
    {
        public int a;
    }
    class Program
    {
        static void Main(string[] args)
        {
            s s1 = new s
                       {
                           a = 1
                       };
            Foo(s1);
            Console.WriteLine("outer a = " + s1.a);
        }
        private static void Foo(s s1)
        {
            s1.a++;
            Console.WriteLine("inner a = " + s1.a);
        }
    }
}

输出是:

inner a = 2
outer a = 1

如何通过引用传递c#结构体

听起来你只是想使用ref通过引用传递结构体:

private static void Foo(ref s s1)
{
    s1.a++;
    Console.WriteLine("inner a = " + s1.a);
}

在呼叫现场:

Foo(ref s1);

请参阅我关于c#中参数传递的文章。

注意,除了互操作,我通常强烈建议而不是使用这样的可变结构体。我能理解这样做的好处。

您可以使用c# 7.2 in关键字如下:

static float Sample(in Vector3 v)
{
    // v.X = 2; // <-- this generate follow compiler error
    // error CS8332: Cannot assign to a member of variable 'v'
    // or use it as the right hand side of a ref assignment
    // because it is a readonly variable
    return v.X;
}

这确保结构体参数v是:

  • 只读的
  • 通过ref

IL细节
Vector3 v = Vector3.One;
float Sample(Vector3 v)
{
    return v.X;
}
System.Console.WriteLine(Sample(v));
float ReadonlySample(in Vector3 v)
{
    return v.X;
}
System.Console.WriteLine(ReadonlySample(v));

produce follow IL:

// Vector3 v2 = Vector3.One;
    IL_0001: call valuetype [System.Numerics.Vectors]System.Numerics.Vector3 [System.Numerics.Vectors]System.Numerics.Vector3::get_One()
    IL_0006: stloc.0
    // Console.WriteLine(Sample(v2));
    IL_0007: nop
    IL_0008: ldloc.0
    IL_0009: call float32 test_console.Sample::'<Main>g__Sample|0_0'(valuetype [System.Numerics.Vectors]System.Numerics.Vector3)
    IL_000e: call void [System.Console]System.Console::WriteLine(float32)
    // (no C# code)
    IL_0013: nop
    // Console.WriteLine(ReadonlySample(in v2));
    IL_0014: nop
    IL_0015: ldloca.s 0
    IL_0017: call float32 test_console.Sample::'<Main>g__ReadonlySample|0_1'(valuetype [System.Numerics.Vectors]System.Numerics.Vector3&)
    IL_001c: call void [System.Console]System.Console::WriteLine(float32)

你可以看到使用in我们用ldloca代替ldloc。

简而言之,该结构体像ref一样传递,但由于in,编译器保护它不能写。