代码之家  ›  专栏  ›  技术社区  ›  John M Gant aman_novice

从C#调用非托管函数:我应该传递StringBuilder还是使用不安全的代码?

  •  6
  • John M Gant aman_novice  · 技术社区  · 15 年前

    这是非托管函数的签名。

    extern "C" __declspec(dllexport) int getNextResponse(char *buffer);
    

    第一个选项是将缓冲区定义为StringBuilder,如下所示。

    //at class level...
    [DllImport("mydll.dll")]
    static extern int getNextResponse(StringBuilder buffer);
    
    //in main method body...
    StringBuilder sb = new StringBuilder(" ", 65536);
    int rc = getNextResponse(sb);
    

    另一种选择是使用不安全代码。

    //at class level...
    [DllImport("mydll.dll")]
    static extern int getNextResponse(byte* buffer);
    
    //separate method...
    private static unsafe int runGetNextResponse(byte[] buffer)
    {
        fixed (byte* p = buffer)
        {
            int rc = getNextResponse(p);
            return rc;
        }            
    }
    
    //in main method body...
    byte[] b = new byte[65536];
    int rc = runGetNextResponse(b);
    

    这两种方法基本上是一样的吗?有什么理由选择一个而不是另一个吗?

    5 回复  |  直到 15 年前
        1
  •  8
  •   chills42    15 年前

    我非常喜欢使用StringBuilder版本。

    这两者之间不会有太大的区别,使用不安全的代码也不是那么干净。

        2
  •  3
  •   Darin Dimitrov    15 年前

    使用StringBuilder是首选,但有一个警告。想象一下,例如,在你的 getNextResponse

    char* globalPointer;
    
    int getNextResponse(char *buffer) {
        globalPointer = buffer;
        return 0;
    }
    
    void someOtherMethod() {
        printf("%s\n", globalPointer);
    }
    

    现在让我们看看托管端:

    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.
    

    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
    }
    

    在这种情况下,不安全版本会更好地工作。

        3
  •  2
  •   Richard Morgan    15 年前

    虽然我不能确切地衡量,但我可以分享我自己的经历。我只使用了StringBuilder方法,没有任何问题。我喜欢它的简单代码和避免不安全的代码。

        4
  •  1
  •   Sheng Jiang 蒋晟    12 年前

    这取决于编组的成本。如果执行了大量封送,或者封送的数据很大,则可能希望重用缓冲区,而不是每次都创建/销毁字符串生成器缓冲区。

        5
  •  0
  •   Stephen Martin    15 年前

    //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);