什么是(fnptr)*类型以及如何创建它?

Ill*_*ack 12 .net c# reflection clr cil

以下IL代码创建一个名为(fnptr)*(标记0x2000000 - 无效,模块mscorlib.dll)的Type实例.

ldtoken method void* ()*
call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
Run Code Online (Sandbox Code Playgroud)

这种类型的目的是什么?是否可以在C#中创建此类型实例而无需编写任何IL代码,也许可以使用反射?令牌上的Module.ResolveType抛出ArgumentOutOfRangeException.

编辑:

很明显,(fnptr)类型是IL方法指针类型的内部CLR类型表示,但是当删除最后一个时*,它只是返回IntPtr.

编辑#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)");
}
Run Code Online (Sandbox Code Playgroud)

为什么基本的fnptr返回IntPtr可以在typehandle.cpp中看到:

OBJECTREF TypeHandle::GetManagedClassObject() const
{
Run Code Online (Sandbox Code Playgroud)

[...]

        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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以看起来他们忘了解决它.

Han*_*ant 5

我不知道你在问什么,为什么你认为有什么不对.(fnptr)*是指向非托管函数指针的指针的类型名称.它在CLR中获得特殊处理确实很奇怪,我怀疑这是一个考古工艺品.可以追溯到.NET之前和代表们发明之前的时间.CLR起源于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;
}
Run Code Online (Sandbox Code Playgroud)

输出: (fnptr)*


Ill*_*ack 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});
Run Code Online (Sandbox Code Playgroud)

6 是字段,15 是指针,27 是函数指针,0、0、1 是不带返回值或参数的方法签名。