创建实现内部接口的类型

本文关键字:类型 接口 内部 实现 创建 | 更新日期: 2023-09-27 18:18:41

假设我有一个声明内部接口IInternalInterface的程序集。我无法访问该程序集的代码,也无法更改它。如何创建自己的IInternalInterface实现?

为什么我需要这个:程序集包含有IInternalInterface实现者列表的类,我的目标是在那里添加我自己的实现。

创建实现内部接口的类型

可以使用远程代理。
请注意,我的回答只是一个简短的概述,可能需要进一步改进。

internal interface IInternalInterface {
    void SayHello();
}
// --------------------------------------------------------------
// in another assembly
public class ImplementationProxy : RealProxy, IRemotingTypeInfo {
    private readonly MethodInfo method;
    public ImplementationProxy(MethodInfo method) 
        : base(typeof(ContextBoundObject))
    {
        this.method = method;
    }
    public override IMessage Invoke(IMessage msg) {
        if (!(msg is IMethodCallMessage))
            throw new NotSupportedException();
        var call = (IMethodCallMessage)msg;
        if (call.MethodBase != this.method)
            throw new NotSupportedException();
        Console.WriteLine("Hi from internals!");
        return new ReturnMessage(null, null, 0, call.LogicalCallContext, call);
    }
    public bool CanCastTo(Type fromType, object o)
    {
        return fromType == method.DeclaringType;
    }
    public string TypeName
    {
        get { return this.GetType().Name; }
        set { }
    }
}    

如何创建我自己的IInternalInterface实现?

简单的回答:你不能。如果程序集的作者决定用internal标记这个接口,这意味着他们不希望其他程序集的代码使用这个接口。

我将扩展@AndreyShchekin的回答,因为它真的很有用,但遗漏了一些位:

public class Program
{
    public static void Main()
    {
        var internalType = typeof(PublicTypeInAnotherAssembly).Assembly.GetType("Full name of internal type: System.Internals.IInterface");
        var result = new InterfaceImplementer(internalType, InterfaceCalled).GetTransparentProxy();
    }
    static object InterfaceCalled(MethodInfo info)
    {
        // Implement logic.
        Console.WriteLine($"{info.Name}: Did someone call an internal method?");
        // Return value matching info.ReturnType or null if void.
        return null;
    }
}
public class InterfaceImplementer : RealProxy, IRemotingTypeInfo
{
    readonly Type _type;
    readonly Func<MethodInfo, object> _callback;
    public InterfaceImplementer(Type type, Func<MethodInfo, object> callback) : base(type)
    {
        _callback = callback;
        _type = type;
    }
    public override IMessage Invoke(IMessage msg)
    {
        var call = msg as IMethodCallMessage;
        if (call == null)
            throw new NotSupportedException();
        var method = (MethodInfo)call.MethodBase;
        return new ReturnMessage(_callback(method), null, 0, call.LogicalCallContext, call);
    }
    public bool CanCastTo(Type fromType, object o) => fromType == _type;
    public string TypeName { get; set; }
}

现在result可分配给内部接口。为了验证它,我们可以在包含内部接口的程序集中执行此操作:

public class PublicTypeInAnotherAssembly
{
    public void Test(object proxy)
    {
        var internalInterface = (IInternalInterface)proxy;
        internalInterface.MethodOnInterface();
    }
}

您还可以使用程序集版本重定向或类型重定向将接口声明"移动"到您控制的程序集,并使您的实现公开。

但是正如Darin所说,一定要仔细考虑这种方法。可能有一种预期的方式来扩展库功能,这样会更干净…

恐怕这是不可能的。即使您设法创建一个使用反射实现该接口的类。Emit,你将无法使用它,因为你会得到一个反射类型异常:Type正试图实现一个不可访问的接口

您可以添加[InternalsVisibleTo()]属性,但就您无法访问源代码而言,您无法在编译时实现该接口

另一方面,您可以在运行时执行为此,您应该使用运行时代码生成(也称为Reflection.Emit)并使用BindingFlags.NonPublic获取接口类型。你可以在这里读到更多。

更新:
正如在下面的评论中提到的,从非公共接口继承是不可能的。所以很不幸,没有解