C#/.NET Generics and Cdecl Varargs Bug?
Why does Foo()
succeed but Bar()
throws a 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, __ar开发者_C百科glist);
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)); }
}
Try like this:
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); }
}
You are asking why an undocumented (_arglist,_makeref,_reftype,_refvalue) keyword does not work.
Well you should ask Microsoft :D
If you really want to know my take on this, it could be because generics don't know the type of T at compile time, and yet they are compiled to classes. What does __arglist take at compilation time there is a mystery. Since in the line where you declare the generic don't specify the kind of parameter to __arglist.
But all of this is as much obscure as using sprintf from C#... at least if it were _snwprintf_s or similar :D
As shown in the following code, the exception is thrown before running the method when it is compiled into native code:
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
Also it is complaining about wrong type passed to SizeOf. I guess it might be a bug in the CLR that causes it to pass the internal handle to the generic type parameter instead of the handle of the real type passed to the method.
精彩评论