我想知道,对于将与PInvoke一起使用的结构/类,使数据成员private
在任何意义上都是非法的。我的动机是在我需要使用的API中有一些相当大的C结构,我宁愿避免为我的PInvoke友好结构中的每一个构造包装器来隐藏数据。与此同时,我不想公开所有数据成员。
尝试一个例子:
C / C ++代码:
//PInvokeProvider.h
#include "stdafx.h"
typedef struct Animal_s
{
char Name[10000];
} Animal;
extern "C" void __declspec(dllexport) ChangeName(Animal* pAnimal);
//PInvokeProvider.cpp
#include "stdafx.h"
#include <stdio.h>
#include "PInvokeProvider.h"
extern "C" {
void ChangeName(Animal* pAnimal)
{
printf("Entered C++\n");
printf("Recieved animal : %s\n", pAnimal->Name);
printf("This function will change the first letter of animal to 'A'\n");
pAnimal->Name[0] = 'A';
printf("Animal changed to : %s\n", pAnimal->Name);
printf("Leaving C++\n");
}
}
C#:
namespace PInvokeConsumer
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Animal
{
/// char[10000]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10000)]
private string _name;
public Animal(string name)
{
_name = name;
}
public string Name
{
get { return _name; }
}
}
public partial class NativeMethods
{
[DllImportAttribute("PInvokeProvider.dll", EntryPoint = "ChangeName", CallingConvention = CallingConvention.Cdecl)]
public static extern void ChangeName(ref Animal pAnimal);
}
internal class Program
{
public static void Main(string[] args)
{
Animal animal = new Animal("Gorilla");
NativeMethods.ChangeName(ref animal);
Console.WriteLine(animal.Name);
Console.Read();
}
}
}
输出:
Entered C++
Recieved animal : Gorilla
This function will change the first letter of animal to 'A'
Animal changed to : Aorilla
Leaving C++
Aorilla
所以在这个例子中,在C#中使用带有私有数据的结构没有任何问题(只要私有数据与C结构的公共数据匹配)。
当我在动物结构上检查Marshal.SizeOf()
时,返回的大小是10,000
等于动物类中唯一存在的数据成员,这让我认为没有任何元的空间数据传递给PInvoke调用,只传递数据位置,这将允许C / C ++代码完全忽略C#中我们的保护级别。关于PInvoke友好结构/类的C#数据成员是否隐私,我还能看到其他问题。
答案 0 :(得分:1)
你问题中的代码很好。编组人员忽略了数据成员的可见性并将其全部编组。私人成员与公共成员一样被编组。
在整个模块边界中,重要的是结构的二进制表示匹配。并且成员的可见性未在二进制表示中编码。结构的二进制表示没有表明成员是私有的。这由具有类型知识的编译器处理。