0

我正在尝试发出以下内容:

这是一个结构,它将作为属性包含在动态发出的类中:

public struct GeoPoint
{
    public double? lat { get; set; }

    public double? lon { get; set; }
}

我必须发出以下课程:

public class GeoPointOwner
{
    public GeoPoint GeoPoint{get; set;}
    public double? Getlat ()
    {
        return GeoPoint.lat;
    }
}

我不知道如何正确发出方法 GeoPointOwner.Getlat

这是我的代码:

var mbGet = typeBuilder.DefineMethod("Getlat", MethodAttributes.Public, typeof(double?), Type.EmptyTypes);
var genGet = mbGet.GetILGenerator();
genGet.Emit(OpCodes.Ldarg_0);
//getMethodInfo below is MethodInfo of Getter of GeoPoint property
genGet.Emit(OpCodes.Call, getMethodInfo);
var getMethod = typeof(GeoPoint).GetProperty("lat").GetGetMethod(true);
//code emitted below fails when invoked
genGet.Emit(OpCodes.Callvirt, getMethod);
genGet.Emit(OpCodes.Stloc_0);
genGet.Emit(OpCodes.Ret);
4

1 回答 1

2

正如我在评论中建议的那样,如果出现这样的错误,最好在生成的程序集中使用 PEVerify。在您的代码上使用它将帮助您修复它。

如果我在生成的程序集上运行它,我会收到以下错误:

[GeoPointOwner::Getlat][offset 0x00000006] 在值类型方法上调用virt。

您不能使用callvirt在值类型上调用方法(在您的情况下,这是 getter for GeoPoint.lat),call而是使用。

修复后,我收到两个新错误:

[GeoPointOwner::Getlat][offset 0x00000006][found value 'ConsoleApplication1.GeoPoint'][expected address of value 'ConsoleApplication1.GeoPoint'] 堆栈上的意外类型。

[GeoPointOwner::Getlat][offset 0x0000000B] 无法识别的局部变量号。

我要先修复第二个。您正在使用stloc_0,它将堆栈顶部的值存储到局部变量#0。它失败了,因为您没有声明任何本地人。我不明白你为什么要这样做,因为你不需要任何当地人。您可以直接返回 的结果call,因此您可以删除stloc_0.

第一个错误更复杂。当你想调用一个值类型的方法时,你实际上需要一个对该类型变量的引用。我们现在没有变量,这意味着我们必须创建一个(使用DeclareLocal()),将值保存到本地(stloc),然后加载该本地的地址(ldloca)。有关更多信息,请参阅问题Method invocation on a struct?.

通过这些更改,您的代码将变为:

var getlatBuilder = type.DefineMethod("Getlat", MethodAttributes.Public, typeof(double?), Type.EmptyTypes);
var il = getlatBuilder.GetILGenerator();
var getPointLocal = il.DeclareLocal(typeof(GeoPoint));

il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, geoPointGetter);

il.Emit(OpCodes.Stloc, getPointLocal);
il.Emit(OpCodes.Ldloca, getPointLocal);

var latGetter = typeof(GeoPoint).GetProperty("lat").GetGetMethod(true);
il.Emit(OpCodes.Call, latGetter);
il.Emit(OpCodes.Ret);
于 2013-01-31T16:58:41.967 回答