C#/.NET 泛型和 Cdecl Varargs 错误?
Posted
技术标签:
【中文标题】C#/.NET 泛型和 Cdecl Varargs 错误?【英文标题】:C#/.NET Generics and Cdecl Varargs Bug? 【发布时间】:2011-08-16 08:51:29 【问题描述】:为什么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));
【问题讨论】:
【参考方案1】:试试这样:
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);
【讨论】:
@Mehrdad,好吧,您正在使用一个未记录的功能,今天它不适用于泛型,明天它可能不适用于其他东西,因为它没有记录,所以没有官方答案。 C#中使用变长参数的方式是使用params
关键字。
如果我使用动态 IL 生成(已记录在案)对您有什么影响吗? (我不知道这是否会出错,但至少它会摆脱这个“它没有记录”的问题......)
@Mehrdad,我仍在尝试找出您要解决的实际问题是什么以及为什么 params
关键字对您不起作用?
从技术上讲,这不再是一个“问题”,因为我找到了解决方法,但它仍然困扰着我,我想知道为什么它首先会发生。【参考方案2】:
您在问为什么未记录的 (_arglist,_makeref,_reftype,_refvalue) 关键字不起作用。
你应该问微软:D
如果你真的想知道我对此的看法,可能是因为泛型在编译时不知道 T 的类型,但它们被编译为类。 __arglist 在编译时需要什么,这是一个谜。因为在声明泛型的行中,不要指定 __arglist 的参数类型。
但所有这些都与使用 C# 中的 sprintf 一样晦涩难懂...至少如果它是 _snwprintf_s 或类似的:D
【讨论】:
@Marino:不确定您所说的“编译时”是什么意思…….NET 中的编译时间几乎没有意义; JIT-time就是事情变得重要的时候,那个时候T
肯定有一个类型...
@Marino:它们完全一样,除了 int32
/!!T
在方法中恰好有 1 个位置不同。
但第二个泛型类 id 编译错误...不是 sprintf 失败,而是泛型类无效..您甚至无法输入泛型方法,...您可能发现了应该报告给微软的错误
@Marino:不知道你所说的“编译错误”是什么意思......你能详细说明一下吗?应该是什么?
这意味着 IL 代码无法运行,而不是 sprintf 无法运行...应该是什么你应该问微软,我不知道文档中没有说明什么,但是我什至无法调试进入第二个泛型方法...【参考方案3】:
如下代码所示,编译成native代码时,方法在运行前抛出异常:
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 中的一个错误,导致它将内部句柄传递给泛型类型参数,而不是传递给方法的真实类型的句柄。
【讨论】:
以上是关于C#/.NET 泛型和 Cdecl Varargs 错误?的主要内容,如果未能解决你的问题,请参考以下文章
使用C#中的自定义数据模型实现泛型和扩展ObservableCollection方法