Skip to main content

How to Resolve Error "CS0662: Cannot specify the Out attribute on a ref parameter without also specifying the In attribute" in C#

The Compiler Error CS0662 is an attribute configuration error related to Interop (Platform Invocation / P/Invoke). The message reads: "Cannot specify the Out attribute on a ref parameter without also specifying the In attribute."

In C#, the ref keyword implies Bidirectional data flow: data goes In from the caller, and potentially different data comes Out from the method. When you apply the [Out] attribute to a ref parameter, you are telling the Marshaler: "Only copy data OUT back to the caller." This contradicts the definition of ref, which requires an initial value to be passed in.

To resolve this, you must either explicitly add the [In] attribute (restoring bidirectional flow) or switch to using the out keyword (if the data flow is truly one-way).

Understanding ref and Marshaling Attributes

The .NET Interop Marshaler uses attributes to optimize how data is copied between Managed (C#) and Unmanaged (C++) memory.

  • ref Keyword: Implicitly means [In, Out]. The value is copied in, modified, and copied back out.
  • [Out] Attribute: Tells the Marshaler to skip the input copy and only handle the output copy.

If you write [Out] ref int x, you create a logical contradiction. You are using ref (which expects an input value) but telling the Marshaler to ignore the input. The compiler forces you to clarify: do you also want [In], or did you use the wrong keyword?

Scenario: The Attribute Conflict

This error typically occurs when defining a DllImport signature and trying to be explicit about marshalling behavior.

Example of error:

using System.Runtime.InteropServices;

public class NativeMethods
{
// ⛔️ Error CS0662: Cannot specify the Out attribute on a ref parameter
// without also specifying the In attribute.
// 'ref' implies the function needs to READ 'value', but '[Out]' says otherwise.
[DllImport("MyLib.dll")]
public static extern void ModifyValue([Out] ref int value);
}

Solution 1: Add the [In] Attribute (Read/Write)

If the native function needs to read the initial value you pass in and then update it, you must keep ref. To satisfy the compiler while keeping [Out], you simply add [In].

Solution:

using System.Runtime.InteropServices;

public class NativeMethods
{
// ✅ Correct: Explicitly stating that data flows both In and Out.
[DllImport("MyLib.dll")]
public static extern void ModifyValue([In, Out] ref int value);
}
note

Note that for simple types (blittable types like int), ref automatically implies [In, Out], so you could also remove the attributes entirely. However, adding them explicitly is valid and often clearer for documentation.

Solution 2: Change ref to out (Write Only)

If the native function ignores the input value and simply writes a result into that memory location, you should not be using ref. You should use the out keyword. The out keyword inherently implies [Out] and does not require [In].

Solution:

using System.Runtime.InteropServices;

public class NativeMethods
{
// ✅ Correct: 'out' matches the semantics of the '[Out]' attribute perfectly.
// No '[In]' is required because the caller doesn't need to initialize it.
[DllImport("MyLib.dll")]
public static extern void GetValue([Out] out int value);
}

Conclusion

CS0662 ensures your Interop definition makes sense.

  1. Check Data Flow: Does the C++ function read the value?
    • Yes: It is an Input/Output parameter. Use [In, Out] ref (or just ref).
    • No: It is a pure Output parameter. Use out (or [Out] out).
  2. Fix Attributes: Never use [Out] alone on a ref parameter. Always pair it with [In].