C# 当PInvoking时,将参数声明为[in]有什么意义吗?

C# 当PInvoking时,将参数声明为[in]有什么意义吗?,c#,pinvoke,marshalling,C#,Pinvoke,Marshalling,使用平台调用时,将参数指定为[In]是否会影响运行时处理这些参数的方式 例如,当PInvokingCreateRemoteThread时,根据MSDN上的文章,lpThreadId被指定为out: HANDLE WINAPI CreateRemoteThread( _In_ HANDLE hProcess, _In_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ SIZE_T dwStackSize, _In_ LP

使用平台调用时,将参数指定为
[In]
是否会影响运行时处理这些参数的方式

例如,当PInvoking
CreateRemoteThread
时,根据MSDN上的文章,
lpThreadId
被指定为
out

HANDLE WINAPI CreateRemoteThread(
  _In_   HANDLE hProcess,
  _In_   LPSECURITY_ATTRIBUTES lpThreadAttributes,
  _In_   SIZE_T dwStackSize,
  _In_   LPTHREAD_START_ROUTINE lpStartAddress,
  _In_   LPVOID lpParameter,
  _In_   DWORD dwCreationFlags,
  _Out_  LPDWORD lpThreadId
);
所有其他参数都是中的
。在我的C#代码中,我像这样处理特定函数:

    [DllImport("kernel32.dll", EntryPoint = "CreateRemoteThread", SetLastError = true)]
    public static extern IntPtr CreateRemoteThread(
        IntPtr hProcess,
        IntPtr lpThreadAttributes,
        uint dwStackSize,
        IntPtr lpStartAddress,
        IntPtr lpParameter,
        uint dwCreationFlags,
        [Out] IntPtr lpThreadId);
[Out]
属性添加到
lpThreadId
,以便运行时知道如何将其封送回调用者。如果我将函数签名更改为:

    [DllImport("kernel32.dll", EntryPoint = "CreateRemoteThread", SetLastError = true)]
    public static extern IntPtr CreateRemoteThread(
        [In] IntPtr hProcess,
        [In] IntPtr lpThreadAttributes,
        [In] uint dwStackSize,
        [In] IntPtr lpStartAddress,
        [In] IntPtr lpParameter,
        [In] uint dwCreationFlags,
        [Out] IntPtr lpThreadId);

或者是完全一样的东西;默认情况下是否将参数视为
[In]

事实上,
[In]
[Out]
属性非常重要,它们告诉框架是否需要关注在特定方向封送参数。这对于诸如
structs
之类的封送非常昂贵的东西特别有用。默认情况下,框架假定封送是双向的,这可能会对性能产生很大影响

更新:
一些注释提出了一个事实,即基本类型在默认情况下被封送为
[In]
,这是正确的。然而,封送处理是复杂的,这让我们有责任在PInvoke声明中尽可能明确,尽可能少地让框架来决定,即使它已经被认为是这样。

事实上,
[in]
[Out]
属性非常重要,它们告诉框架是否需要关注在特定方向封送参数。这对于诸如
structs
之类的封送非常昂贵的东西特别有用。默认情况下,框架假定封送是双向的,这可能会对性能产生很大影响

更新:

一些注释提出了一个事实,即基本类型在默认情况下被封送为
[In]
,这是正确的。然而,封送处理是复杂的,这让我们有责任在PInvoke声明中尽可能明确,尽可能少地让框架来决定,即使它已经被认为是这样。

您可能希望
out
ref
最后一个。但是
[In]
本身是如此。@user7116实际上不是真的,任何封送为指针的东西都应该使用
[In]
[Out]
属性。@Mgetz仅对指针很重要,如果是这样,为什么?@aevitas指针,如
string
和传入的任何
struct
s,例如,除基元类型以外的任何数据结构。您可能希望
out
ref
。但是
[In]
本身是如此。@user7116实际上不是真的,任何封送为指针的东西都应该使用
[In]
[Out]
属性。@Mgetz仅对指针很重要,如果是这样,为什么?@aevitas指针,如
string
和传入的任何
struct
s,例如原始类型以外的任何数据结构。因此,如果我答对了,将参数指定为
[in]
会告诉运行时,它永远不需要将这些值封送回调用方,因此理论上应该提高性能?@aevitas正确,它告诉框架参数只在一个方向上封送。
[in]
是大多数参数类型的默认值。@user7116不正确,
[in,Out]
是所有非原语的默认值。实际上,
string
是一个糟糕的例子,因为它总是
[In]
,即使您要求也无法编组
[Out]
。因此,如果我得到正确答案,请将参数指定为
[In]
告诉运行时,它永远不需要将这些值封送回调用者,因此理论上应该可以提高性能?@aevitas correct,它告诉框架参数只在一个方向封送。
[in]
是大多数参数类型的默认值。@user7116不正确,
[in,Out]
是所有非基本元素的默认值。实际上,
string
是一个糟糕的示例,因为它总是
[In]
,即使您要求,也无法编组
[Out]