C# 为什么';封送的对象是否保留在本机代码中修改的值?

C# 为什么';封送的对象是否保留在本机代码中修改的值?,c#,marshalling,C#,Marshalling,我相信有一个简单的答案,但经过一些研究后我找不到。我读取并证明(除非我写的是错误的),通过分配在托管内存中的引用(或类)自动封送的结构由本机代码正确读取和写入,但是一旦代码执行返回到托管层,本机代码中更改的值就不会保留。这里有一个例子: [StructLayout(LayoutKind.Sequential, Pack = 1)] public class DirtyWordsCheckResult { [MarshalAs(UnmanagedType.ByValTStr, Si

我相信有一个简单的答案,但经过一些研究后我找不到。我读取并证明(除非我写的是错误的),通过分配在托管内存中的引用(或类)自动封送的结构由本机代码正确读取和写入,但是一旦代码执行返回到托管层,本机代码中更改的值就不会保留。这里有一个例子:

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
public class DirtyWordsCheckResult
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
    public string replace_string;
    public EnumDirtyWordsType dirty_type;

    public DirtyWordsCheckResult()
    {
        replace_string = new string(' ', 1024);
    }
}

public enum EnumDirtyWordsType
{
    kDirtyWordsTypeNormalAllowWords = 0,   // normal allow words
    kDirtyWordsTypeEvil = 1,               // illegal,can not be displayed
    kDirtyWordsTypeSensitive = 2,          // legal, but contain sensitive
}

public override EResult DirtyWordsFilter(string words, bool replace_sensitive, out DirtyWordsCheckResult check_result)
{
    check_result = new DirtyWordsCheckResult();
    var result = Utils.DirtyWordsFilter(utils_, words, replace_sensitive, check_result);
    return result;
}
本机函数DirtyWordsFilter确实能够正确获取分配的对象,并且可以毫无问题地写入其中,但是不会保留值

现在我知道我可以使用Marshal.AllocHGlobal来传递预分配的IntPTR,因此我不是在寻找解决方案,我只是想了解为什么原始机制不起作用。

您使用的结构是不可blittable的。一个昂贵的词,表示本机布局与托管布局不同。字符串导致它。不仅仅是因为字符集的缘故,.NET字符串看起来不像char[]。这需要pinvoke封送拆收器在传递本机代码可以使用的指针之前创建正确大小的副本

但默认情况下,它不会将修改后的结构复制回来。您必须在参数上添加
[Out]
,使其改变主意。我们看不到[DllImport]声明,但它应该类似于:

[DllImport(...)]
private static extern EResult DirtyWordsFilter(..., [Out] DirtyWordsCheckResult check_result);  

pinvoke marshaller对数据流没有特定的知识,即使在声明中使用
ref
out
(通常用于结构声明)。它只看到通过引用传递的参数,并假定
[In]
为默认值。通常是正确的最佳猜测,而不是这里。Fwiw,注意Pack=1几乎从来都不正确,它需要匹配本机代码中使用的打包,默认值也是8。在这种特殊情况下,发生这种情况并不重要。

应该使用的是或。在回答中,您似乎使用了这两种方法。引用:“您必须在参数上输入
[Out]
”。方括号==属性。好的,我一开始在理解最后一段的前3个句子时遇到困难。我现在明白你的意思了。