lunatix
lunatix

Reputation: 807

Is it safe to pass a struct with "ref this" to native code

I am currently integrating the Steamworks SDK into my game and have a couple of methods which require to pass a struct as a pointer, for example:

// Public interface method declared by the library
S_API bool SteamAPI_SteamNetworkingIPAddr_IsLocalHost( SteamNetworkingIPAddr* self );
// C# implementation

[StructLayout(LayoutKind.Explicit, Size = 18, Pack = 1)]
public struct SteamNetworkingIPAddr {

    // My current usage of "ref this"
    public bool IsLocalhost => NativeMethods.SteamAPI_SteamNetworkingIPAddr_IsLocalHost(ref this);

    // How another library solves it
    public bool IsLocalhost {
        get {
            SteamNetworkingIPAddr copy = this;
            NativeMethods.SteamAPI_SteamNetworkingIPAddr_IsLocalHost(ref self);
        }
    }


    private static class NativeMethods {
        [DllImport(SteamAPI.LIBRARY_NAME, EntryPoint = "SteamAPI_SteamNetworkingIPAddr_IsLocalHost", CallingConvention = CallingConvention.Cdecl)]
        internal static extern bool SteamAPI_SteamNetworkingIPAddr_IsLocalHost(ref SteamNetworkingIPAddr self);
    }
}

I am a bit concerned about passing this with ref to the native method because I've seen other implementations which create a copy of the struct before passing it but I could not find something which officially says that it's either safe or unsafe to do so.

So, my question is - should I make a copy or keep my solution?

Upvotes: 1

Views: 314

Answers (1)

Charlieface
Charlieface

Reputation: 71578

In a instance method or property of a struct, the implicit this parameter is a ref managed reference. So any changes to the struct do mutate (change) the struct passed in.

Therefore, when you call the native function, you are passing an actual reference to your own struct. So it is possible for your caller to see these changes, if they have passed in a reference to their own struct. But depending on how your caller makes this call, there may be a defensive copy anyway.

For example:

var isLocal = SomeClass.IPAddrProperty.IsLocalhost

this will create a copy of the struct, and any changes will disappear.

Whereas this:

var ipAddr = SomeClass.IPAddrProperty;
var isLocal = ipAddr.IsLocalhost;
SomeClass.IPAddrProperty = ipAddr;

means that the results are copied back.

Upvotes: 1

Related Questions