Calling unmanaged function from C#: should I pass StringBuilder or use unsafe code?

人走茶凉 提交于 2019-12-05 08:04:09

I'd strongly prefer using the StringBuilder version.

There's not going to be a huge difference between the two, and using unsafe code is not nearly as clean.

In my opinion, since there is a way to solve the problem using a core library class, using unsafe code without a clear (and needed) benefit is a premature optimization.

While using a StringBuilder is preferred there's one caveat. Imagine for example that in your getNextResponse method you store the pointer to some static variable and use it in another method:

char* globalPointer;

int getNextResponse(char *buffer) {
    globalPointer = buffer;
    return 0;
}

void someOtherMethod() {
    printf("%s\n", globalPointer);
}

Now let's look at the managed side:

var sb = new StringBuilder();
sb.Append("Hello World");
int result = getNextResponse(sb);
Console.WriteLine(result);
someOtherMethod(); // kaboom: The GC could have already destroyed the string builder.

The unsafe method guarantees you that the memory location won't be moved around:

byte[] buffer = Encoding.UTF8.GetBytes("Hello World");
fixed (byte* p = buffer)
{
    int result = getNextResponse(p);
    Console.WriteLine(result);
    someOtherMethod(); // works fine as the buffer address is pinned down in memory
}

In this case the unsafe version will work better.

While I can't weigh in definitively, I can share my own experiences. I have used the StringBuilder method exclusively and have had no problems with it. I like the simpler code of it and the avoidance of unsafe.

It depends on the cost of marshalling. If you do a lot of marshalling or the data being marshalled is large, you may want to reuse the buffer instead of creating/destroying the string builder buffer every time.

It depends on what the data in the buffer actually is. If it is character data use the StringBuilder approach. If it is binary data use a byte array instead, but don't use the unsafe method. While the exaggerated fear of 'unsafe' that is getting common is a little silly and there is no reason not to use it when warranted, in this case it is unnecessary. Use:

//at class level...
[DllImport("mydll.dll")]
static extern int getNextResponse([In, Out] byte[] buffer);

//in main method body...
byte[] buffer = new byte[65536];
int rc = getNextResponse(buffer);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!