Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在.NET中创建DynamicType实现接口但使用基类的成员实现_.net_Cil - Fatal编程技术网

在.NET中创建DynamicType实现接口但使用基类的成员实现

在.NET中创建DynamicType实现接口但使用基类的成员实现,.net,cil,.net,Cil,我试图生成一个实现接口的动态类,但其中一个或多个成员已经存在于基类中。我在C#中编译了以下代码,并在reflector中对其进行了检查,以了解C#编译器的功能 class BaseClass { public string Bob { get { return "Bob"; } } } interface IStuff { string Bob { get; } } class SubClass : BaseClass, IStuff { }

我试图生成一个实现接口的动态类,但其中一个或多个成员已经存在于基类中。我在C#中编译了以下代码,并在reflector中对其进行了检查,以了解C#编译器的功能

class BaseClass
{
    public string Bob
    {
        get { return "Bob"; }
    }
}

interface IStuff
{
    string Bob { get; }
}

class SubClass : BaseClass, IStuff
{
}
Reflector未在子类中显示任何实现

.class private auto ansi beforefieldinit SubClass
    extends Enterprise.Services.OperationalActions.Business.Filters.BaseClass
    implements Enterprise.Services.OperationalActions.Business.Filters.IStuff
{
}

但是如果我没有显式地发出该成员,
TypeBuilder.CreateType()
抛出一个
InvalidOperationException
,声明该成员没有实现。所以我的问题是,我如何告诉
TypeBuilder
接口成员应该从基础上获取它的实现?

看起来,使用
TypeBuilder
您必须添加一个私有传递,以使其满意(见下文)。您也可以尝试使用几乎相同的构建器API,但它可能没有这个限制

using System;
using System.Reflection;
using System.Reflection.Emit;
public class BaseClass
{
    public string Bob
    {
        get { return "Bob"; }
    }
}

public interface IStuff
{
    string Bob { get; }
}
static class Program
{
    static void Main()
    {
        var name = new AssemblyName("foo");
        var asm = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
        var mod = asm.DefineDynamicModule("foo");
        var parent = typeof(BaseClass);
        var type = mod.DefineType("SubClass", parent.Attributes, parent);
        type.AddInterfaceImplementation(typeof(IStuff));

        var bob_get = type.DefineMethod("bob_get", MethodAttributes.Virtual | MethodAttributes.Private,
            typeof(string), Type.EmptyTypes);
        var il = bob_get.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.EmitCall(OpCodes.Callvirt, parent.GetProperty("Bob").GetGetMethod(), null);
        il.Emit(OpCodes.Ret);
        type.DefineMethodOverride(bob_get, typeof(IStuff).GetProperty("Bob").GetGetMethod());
        var final = type.CreateType();
        IStuff obj = (IStuff) Activator.CreateInstance(final);
        Console.WriteLine(obj.Bob);
    }
}
C#编译器实际上为
BaseType
发出不同的代码,这取决于
子类定义是否在同一程序集中。所以如果你有这个:

interface IStuff
{
    string Bob { get; }
}

public class BaseClass
{
    public string Bob
    {
        get { return "Bob"; }
    }
}
然后在另一个C#项目中定义
子类
,那么编译器实际上会在其中发出一个显式接口实现。这是因为在本例中,
BaseClass.get\u Bob
将被定义为非虚拟,这意味着它不能用于满足接口的约定


另请参见,它在回答的末尾明确讨论了这种奇怪现象。

您的代码示例没有显示
子类实现
IStuff
。你的意思是写
类的子类:BaseClass,IStuff
?谢谢,很遗憾我需要一个包装器属性,但这仍然足以满足我的需要。我原以为接口的vtable记录将简单地指向按BaseClass实现。当我今晚回家的时候,我必须浏览一下这个链接,看起来它可能会很有趣。@Brian-我相信只有虚拟方法出现在子类的方法表的一致插槽中。因此,对于指向
基类
的方法表中也适用于子类的插槽的接口,该方法必须是虚拟的,这就是为什么IL中的所有接口方法实现都必须是虚拟的(尽管C#编译器不要求您这样注释它们)。