C#/。NET Generics和Cdecl Varargs Bug?

时间:2011-05-01 07:27:33

标签: c# .net generics variadic-functions cdecl

为什么Foo()成功,但Bar()会引发BadImageFormatException

using System.Runtime.InteropServices;
using System.Text;

static class Program
{
    [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
    static extern int sprintf([Out] StringBuilder buf, string format, __arglist);

    static void Main(string[] args)
    {
        Foo<int>(2); //Runs fine
        Bar<int>(2); //Error: "The signature is incorrect"
    }

 static void Foo<T>(int a) { sprintf(new StringBuilder(8), "%d", __arglist(a)); }
 static void Bar<T>(T   a) { sprintf(new StringBuilder(8), "%d", __arglist(a)); }
}

3 个答案:

答案 0 :(得分:0)

试试这样:

using System;
using System.Runtime.InteropServices;
using System.Text;

static class Program
{
    [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
    static extern int sprintf([Out] StringBuilder buf, string format, params object[] args);

    static void Main(string[] args)
    {
        Foo(2);
        Bar<int>(2);
    }

    static void Foo(int a) { sprintf(new StringBuilder(8), "%d", a); }
    static void Bar<T>(T a){ sprintf(new StringBuilder(8), "%d", a); }
}

答案 1 :(得分:0)

您在问为什么未记录的(_ arglist, _makeref,_ reftype, _refvalue)关键字不起作用。

你应该问微软:D

如果你真的想知道我对此的看法,可能是因为泛型在编译时不知道T的类型,但它们被编译成类。 __arglist在编译时采取了什么有一个谜。因为在声明泛型的行中没有指定__arglist的参数类型。

但所有这些都与使用C#中的sprintf一样模糊......至少如果它是_snwprintf_s或类似的话:D

答案 2 :(得分:0)

如下面的代码所示,在将方法编译为本机代码之前运行该方法时抛出异常:

var t = typeof(Program);
var m = t.GetMethod("Bar", BindingFlags.NonPublic | BindingFlags.Static);
m = m.MakeGenericMethod(typeof(int));
System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod(m.MethodHandle); //error

此外,它抱怨传递给 SizeOf 的错误类型。我想这可能是CLR中的一个错误导致它将内部句柄传递给泛型类型参数而不是传递给方法的实际类型的句柄。