C#:编组结构数组,其中包含从 Unity 中的 C++/ObjectiveC 到 C# 的字符串
C#: Marshall array of structs with strings from C++/ObjectiveC in Unity to C#
我正在尝试将 ObjectiveC/C++ 创建的带有字符串的结构数组编组到 C# 中,但我没有成功。大多数时候 C# 编组找不到 "value" 字符串字段。这是迄今为止我得到的最好的:
C# 结构:
private struct Entry
{
public string Key;
public string Value;
}
C#代码
public Dictionary<string, string> Convert()
{
var dic = new Dictionary<string, string>();
getEntries(NativeInstance, out IntPtr pUnmanagedStringArray, out int keysCount);
IntPtr[] pIntPtrArray = new IntPtr[keysCount];
Entry[] entriesInDictionary = new Entry[keysCount];
// I'm not really sure I've done this correctly?
Marshal.Copy(pUnmanagedStringArray, pIntPtrArray, 0, keysCount);
for (int i = 0; i < keysCount; i++)
{
Debug.Log("Iter " + i);
// I'm not really sure I've done this correctly?
entriesInDictionary[i] = Marshal.PtrToStructure<Entry>(pIntPtrArray[i]);
}
Marshal.FreeHGlobal(pUnmanagedStringArray); // Free native malloc for array
foreach (var entry in entriesInDictionary)
{
Debug.Log("Entry" + entry.Key);
Debug.Log("Value" + entry.Value);
//dic.Add(entry.key, entry.value);
}
return dic;
}
C++/ObjectiveC
struct Entry {
const char* key;
const char* value;
};
void getEntries(NSDictionary* dictionary, const Entry* &_entries, int &size) {
int count = (int) [dictionary count];
Entry* entries = (Entry*) malloc(count * sizeof(Entry) );
int i = 0;
for(id key in dictionary) {
id value = [dictionary objectForKey:key];
entries[i].key = Utils::mallocCharStr(key); // malloc char* from NSString.
entries[i].value = Utils::mallocCharStr(value); // malloc char* from NSString.
++i;
}
_entries = entries;
size = count;
}
此时我很迷茫,我尝试了不同的组合。我也为两个字符串尝试了一个 IntPtr 结构,但后来我确定 "value" 指针是 0.
有什么想法吗?
我发现了问题。我的问题是我如何 create/read 结构数组。在最初的 C# 实现中,预期给定数组是指向结构的指针数组,但本机代码创建了一个包含结构本身的数组。
这个问题可以用两种不同的方法解决。更新 C++ 代码以创建指向结构的指针数组:
void getEntries(NSDictionary* dictionary, Entry** &_entries, int &size) {
int count = (int) [dictionary count];
// Array of pointers! Structs will be malloc-ed individually on the loop.
Entry** entries = (Entry**) malloc(count * sizeof(Entry*) );
int i = 0;
for(id key in dictionary) {
id value = [dictionary objectForKey:key];
// It creates a pointer to the struct
entries[i] = (Entry*) malloc(sizeof(Entry));
entries[i]->key = Utils::mallocCharStr(key);
entries[i]->value = Utils::mallocCharStr(value);
++i;
}
_entries = entries;
size = count;
}
C# 的处理方式是:
public Dictionary<string, string> Convert()
{
var dic = new Dictionary<string, string>();
getEntries(NativeInstance, out IntPtr pUnmanagedArray, out int keysCount);
IntPtr[] pIntPtrArray = new IntPtr[keysCount];
// This was the original problem.
// Now it copies the native array pointers to individual IntPtr. Which now they point to individual structs.
Marshal.Copy(pUnmanagedArray, pIntPtrArray, 0, keysCount);
for (int i = 0; i < keysCount; i++)
{
Entry entry = Marshal.PtrToStructure<Entry>(pIntPtrArray[i]); // Magic!
dic.Add(entry.Key, entry.Value);
Marshal.FreeHGlobal(pIntPtrArray[i]); // Free the individual struct malloc
}
Marshal.FreeHGlobal(pUnmanagedArray); // Free native array of pointers malloc.
return dic;
}
==
另一种可能的解决方案是保持 C++ 在原始问题上的方式。所以这意味着本机代码创建了一个结构数组(不是指针)。但是随后需要更新 C# 代码 以正确偏移数组中的每个项目。
public Dictionary<string, string> Convert()
{
var dic = new Dictionary<string, string>();
getEntries(NativeInstance, out IntPtr pUnmanagedArray, out int keysCount);
// Note that we don't use Marshal.Copy(...).
// Every item in the array has an memory offset of the size of the struct, rather than the size of the pointer to a struct.
for (int i = 0; i < keysCount; i++)
{
// "Selects" the nth structure by offseting the original pointer element:
IntPtr pCurrent = pUnmanagedArray + i * Marshal.SizeOf(typeof(Entry));
Entry entry = Marshal.PtrToStructure<Entry>(pCurrent);
dic.Add(entry.Key, entry.Value);
}
// It only frees the array of struct itself because it contains the structs themselves.
Marshal.FreeHGlobal(pUnmanagedArray);
return dic;
}
请注意,在执行自动封送处理时,结构的字符串会自动释放。
我正在尝试将 ObjectiveC/C++ 创建的带有字符串的结构数组编组到 C# 中,但我没有成功。大多数时候 C# 编组找不到 "value" 字符串字段。这是迄今为止我得到的最好的:
C# 结构:
private struct Entry
{
public string Key;
public string Value;
}
C#代码
public Dictionary<string, string> Convert()
{
var dic = new Dictionary<string, string>();
getEntries(NativeInstance, out IntPtr pUnmanagedStringArray, out int keysCount);
IntPtr[] pIntPtrArray = new IntPtr[keysCount];
Entry[] entriesInDictionary = new Entry[keysCount];
// I'm not really sure I've done this correctly?
Marshal.Copy(pUnmanagedStringArray, pIntPtrArray, 0, keysCount);
for (int i = 0; i < keysCount; i++)
{
Debug.Log("Iter " + i);
// I'm not really sure I've done this correctly?
entriesInDictionary[i] = Marshal.PtrToStructure<Entry>(pIntPtrArray[i]);
}
Marshal.FreeHGlobal(pUnmanagedStringArray); // Free native malloc for array
foreach (var entry in entriesInDictionary)
{
Debug.Log("Entry" + entry.Key);
Debug.Log("Value" + entry.Value);
//dic.Add(entry.key, entry.value);
}
return dic;
}
C++/ObjectiveC
struct Entry {
const char* key;
const char* value;
};
void getEntries(NSDictionary* dictionary, const Entry* &_entries, int &size) {
int count = (int) [dictionary count];
Entry* entries = (Entry*) malloc(count * sizeof(Entry) );
int i = 0;
for(id key in dictionary) {
id value = [dictionary objectForKey:key];
entries[i].key = Utils::mallocCharStr(key); // malloc char* from NSString.
entries[i].value = Utils::mallocCharStr(value); // malloc char* from NSString.
++i;
}
_entries = entries;
size = count;
}
此时我很迷茫,我尝试了不同的组合。我也为两个字符串尝试了一个 IntPtr 结构,但后来我确定 "value" 指针是 0.
有什么想法吗?
我发现了问题。我的问题是我如何 create/read 结构数组。在最初的 C# 实现中,预期给定数组是指向结构的指针数组,但本机代码创建了一个包含结构本身的数组。
这个问题可以用两种不同的方法解决。更新 C++ 代码以创建指向结构的指针数组:
void getEntries(NSDictionary* dictionary, Entry** &_entries, int &size) {
int count = (int) [dictionary count];
// Array of pointers! Structs will be malloc-ed individually on the loop.
Entry** entries = (Entry**) malloc(count * sizeof(Entry*) );
int i = 0;
for(id key in dictionary) {
id value = [dictionary objectForKey:key];
// It creates a pointer to the struct
entries[i] = (Entry*) malloc(sizeof(Entry));
entries[i]->key = Utils::mallocCharStr(key);
entries[i]->value = Utils::mallocCharStr(value);
++i;
}
_entries = entries;
size = count;
}
C# 的处理方式是:
public Dictionary<string, string> Convert()
{
var dic = new Dictionary<string, string>();
getEntries(NativeInstance, out IntPtr pUnmanagedArray, out int keysCount);
IntPtr[] pIntPtrArray = new IntPtr[keysCount];
// This was the original problem.
// Now it copies the native array pointers to individual IntPtr. Which now they point to individual structs.
Marshal.Copy(pUnmanagedArray, pIntPtrArray, 0, keysCount);
for (int i = 0; i < keysCount; i++)
{
Entry entry = Marshal.PtrToStructure<Entry>(pIntPtrArray[i]); // Magic!
dic.Add(entry.Key, entry.Value);
Marshal.FreeHGlobal(pIntPtrArray[i]); // Free the individual struct malloc
}
Marshal.FreeHGlobal(pUnmanagedArray); // Free native array of pointers malloc.
return dic;
}
==
另一种可能的解决方案是保持 C++ 在原始问题上的方式。所以这意味着本机代码创建了一个结构数组(不是指针)。但是随后需要更新 C# 代码 以正确偏移数组中的每个项目。
public Dictionary<string, string> Convert()
{
var dic = new Dictionary<string, string>();
getEntries(NativeInstance, out IntPtr pUnmanagedArray, out int keysCount);
// Note that we don't use Marshal.Copy(...).
// Every item in the array has an memory offset of the size of the struct, rather than the size of the pointer to a struct.
for (int i = 0; i < keysCount; i++)
{
// "Selects" the nth structure by offseting the original pointer element:
IntPtr pCurrent = pUnmanagedArray + i * Marshal.SizeOf(typeof(Entry));
Entry entry = Marshal.PtrToStructure<Entry>(pCurrent);
dic.Add(entry.Key, entry.Value);
}
// It only frees the array of struct itself because it contains the structs themselves.
Marshal.FreeHGlobal(pUnmanagedArray);
return dic;
}
请注意,在执行自动封送处理时,结构的字符串会自动释放。