以下IL代码创建名为(fnptr)*
的Type实例(令牌0x2000000 - 无效,模块mscorlib.dll)。
ldtoken method void* ()*
call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
这种类型的目的是什么?是否可以在C#中创建此类型实例而无需编写任何IL代码,也许可以使用反射?令牌上的 Module.ResolveType 会抛出 ArgumentOutOfRangeException 。
编辑:
很明显(fnptr)
类型是IL方法指针类型的内部CLR类型表示,但是当删除最后一个*
时,它只返回IntPtr
。< / p>
编辑#2:
(fnptr)
来自SSCLI typestring.cpp 中可以看到的函数:
// ...or function pointer else if (ty.IsFnPtrType()) { // Don't attempt to format this currently, it may trigger GC due to fixups. tnb.AddName(L"(fnptr)"); }
为什么基本的fnptr返回IntPtr可以在 typehandle.cpp 中看到:
OBJECTREF TypeHandle::GetManagedClassObject() const {
[...]
switch(GetInternalCorElementType()) { case ELEMENT_TYPE_ARRAY: case ELEMENT_TYPE_SZARRAY: case ELEMENT_TYPE_BYREF: case ELEMENT_TYPE_PTR: return ((ParamTypeDesc*)AsTypeDesc())->GetManagedClassObject(); case ELEMENT_TYPE_VAR: case ELEMENT_TYPE_MVAR: return ((TypeVarTypeDesc*)AsTypeDesc())->GetManagedClassObject(); // for this release a function pointer is mapped into an IntPtr. This result in a loss of information. Fix next release case ELEMENT_TYPE_FNPTR: return TheIntPtrClass()->GetManagedClassObject(); default: _ASSERTE(!"Bad Element Type"); return NULL; } } }
所以看起来他们已经忘记了解决它。
答案 0 :(得分:5)
我不知道你在问什么,为什么你认为有什么不对。 (fnptr)*是指向非托管函数指针的指针的类型名称。它在CLR中获得特殊处理确实很奇怪,我怀疑这是一个考古工艺品。可以追溯到.NET之前和代表们发明之前的时间。 CLR起源于&#34;通用运行时&#34;在Project 42中,.NET之前的项目失败。
也许一些C ++ / CLI代码演示如何生成一个很有用,向您展示如何创建它:
#include "stdafx.h"
using namespace System;
typedef void (*functionPointer)(int);
ref class Example {
public:
functionPointer* fp;
};
int main(array<System::String ^> ^args)
{
auto field = Example::typeid->GetField("fp");
auto name = field->FieldType->FullName;
Console::WriteLine(name);
return 0;
}
输出:(fnptr)*
答案 1 :(得分:0)
不确定您在哪里看到FNPTR被宣布。
对于此代码:
.assembly extern mscorlib {}
.assembly Test
{
.ver 1:0:1:0
}
.module test.exe
.method static void main() cil managed
{
.maxstack 1
.entrypoint
ldtoken method void* ()*
call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
ldtoken method void* ()
call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
ret
}
ILASM(4.5.22.0)输出以下内容:
.method privatescope static void main$PST06000001() cil managed
{
.entrypoint
// Code size 21 (0x15)
.maxstack 1
IL_0000: ldtoken method void *()*
IL_0005: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_000a: ldtoken method void *()
IL_000f: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0014: ret
} // end of method 'Global Functions'::main
也许我在这里很密集,但我没有看到从这段代码生成FNPTR:
typeof(StringBuilder).ToString();
IL看起来像这样:
IL_0000: nop
IL_0001: ldtoken [mscorlib]System.Text.StringBuilder
IL_0006: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_000b: callvirt instance string [mscorlib]System.Object::ToString()
IL_0010: pop
IL_0011: ret
自ToString() is a virtual method以来,Type.ToString()
来电是callvirt
来电。
虚函数通常表现为函数指针的结构,我想这会导致FNPTR被发出。如果省略导致*
的{{1}}中的()*
,您现在正在描述函数,而不是函数指针。
当您看到FNPTR时,您使用的是什么版本的.NET?你用什么来提取IL?
答案 2 :(得分:0)
可以将指针的签名加载到函数指针:
public static unsafe Type GetTypeFromFieldSignature(byte[] signature, Type declaringType = null)
{
declaringType = declaringType ?? typeof(object);
Type sigtype = typeof(Type).Module.GetType("System.Signature");
Type rtype = typeof(Type).Module.GetType("System.RuntimeType");
var ctor = sigtype.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new[]{typeof(void*), typeof(int), rtype}, null);
fixed(byte* ptr = signature)
{
object sigobj = ctor.Invoke(new object[]{(IntPtr)ptr, signature.Length, declaringType});
return (Type)sigtype.InvokeMember("FieldType", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty, null, sigobj, null);
}
}
var fnptrPtr = GetTypeFromFieldSignature(new byte[]{6, 15, 27, 0, 0, 1});
6是字段,15是指针,27是函数指针,0,0,1是没有返回或参数的方法签名。