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

发布于 2024-10-14 04:22:27 字数 704 浏览 5 评论 0原文

我正在尝试生成一个实现接口的动态类,但其中一个或多个成员已存在于基中。我用 C# 编译了以下代码,并在反射器中检查了它,看看 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 接口成员应该从基础获取它的实现?

I am attempting to generate a dynamic class implementing an interface, but where one or more of the members already exists in the base. I compiled the following code in C# and examined it in reflector to see what the C# compiler does.

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

interface IStuff
{
    string Bob { get; }
}

class SubClass : BaseClass, IStuff
{
}

Reflector does not show any implementation in SubClass.

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

But if I do not emit the member explicitly, TypeBuilder.CreateType() throws an InvalidOperationException stating that the member does not have an implementation. So my question is, how do I tell TypeBuilder that an interface member should take it's implementation from the base?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

許願樹丅啲祈禱 2024-10-21 04:22:28

C# 编译器实际上会为 BaseType 发出不同的代码,具体取决于您的 SubClass 定义是否位于同一个程序集中。因此,如果您只有这样:

interface IStuff
{
    string Bob { get; }
}

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

然后在另一个 C# 项目中定义 SubClass,那么编译器实际上会在其中发出显式接口实现。这是因为在这种情况下,BaseClass.get_Bob 将被定义为非虚拟,这意味着它不能用于满足接口的约定。

另请参阅 为什么 C# 接口方法不是声明为抽象还是虚拟?,它在答案的末尾明确讨论了这种奇怪的情况。

The C# compiler actually emits different code for BaseType depending on whether your SubClass definition is in the same assembly or not. So if you just have this:

interface IStuff
{
    string Bob { get; }
}

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

and then define SubClass in another C# project, then the compiler will actually emit an explicit interface implementation within it. This is because in this case, BaseClass.get_Bob will be defined as non-virtual, which means that it can't be used to satisfy the interface's contract.

See also Why are C# interface methods not declared abstract or virtual?, which explicitly discusses this oddity at the end of the answer.

二智少女 2024-10-21 04:22:27

看起来使用 TypeBuilder 您必须添加一个私有传递,只是为了让它满意(如下)。您还可以尝试使用 IKVM 构建器 - 几乎相同的 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);
    }
}

It looks like with TypeBuilder you will have to add a private pass-thru, just to make it happy (below). You could also try using the IKVM builder - almost identical API, but it might not have this limitation.

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);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文