简体   繁体   English

创建实现内部接口的类型

[英]Create type that implements internal interface

Suppose I have assembly that declares internal interface IInternalInterface . 假设我有声明内部接口IInternalInterface程序集。 I have no access to code of this assembly and I can't change it. 我无法访问此程序集的代码,我无法更改它。 How can I create my own implementation of IInternalInterface ? 如何创建自己的IInternalInterface实现?

Why I need this: the assembly contains the class with list of IInternalInterface implementers and my goal is to add my own implementation there. 为什么我需要这个:程序集包含带有IInternalInterface实现者列表的类,我的目标是在那里添加我自己的实现。

It is possible using remoting proxy. 可以使用远程代理。
Note that my answer is just a quick sketch and might need to be improved further. 请注意,我的答案只是一个快速草图,可能需要进一步改进。

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 { }
    }
}    

I will extend the answer from @AndreyShchekin as it was really useful but missed some bits: 我将扩展@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; }
}

Now result is assignable to the internal interface. 现在result可分配给内部接口。 To verify it, we can do this in the assembly containing the internal interface: 要验证它,我们可以在包含内部接口的程序集中执行此操作:

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

        internalInterface.MethodOnInterface();
    }
}

Or assign it with reflection if we don't have access. 如果我们没有访问权限,请为其分配反射

How can I to create my own implementation of IInternalInterface? 我怎样才能创建自己的IInternalInterface实现?

Simple answer: you can't. 简单回答:你做不到。 If the authors of the assembly decided to mark this interface with internal it means that they didn't want code from other assemblies to use this interface. 如果程序集的作者决定用internal标记此接口,则意味着他们不希望其他程序集中的代码使用此接口。

You could also use assembly version redirection or type redirection to "move" the interface declaration to an assembly under your control and make your implementation public. 您还可以使用程序集版本重定向或类型重定向将接口声明“移动”到您控制下的程序集,并使您的实现公开。

But as Darin said, be sure to double-think about this approach. 但正如达林所说,一定要仔细考虑这种方法。 There may be an intended way to extend the library functionality that would be much cleaner... 可能有一种扩展库功能的预期方法会更清晰......

I am afraid this is impossible. 我担心这是不可能的。 Even if you manage to make a class that implements that interface using Reflection.Emit, you won't be able to use it because you will get a ReflectionTypeLoadException: Type is attempting to implement an inaccessible interface 即使您设法使用Reflection.Emit创建一个实现该接口的类,您也将无法使用它,因为您将获得ReflectionTypeLoadException:Type正在尝试实现一个不可访问的接口

You could add [InternalsVisibleTo()] attribute, but as far as you have no access to source code, you can't implement this interface at compile time 您可以添加[InternalsVisibleTo()]属性,但只要您无法访问源代码, 就无法在编译时实现此接口

From the other hand, you can do it at run time. 另一方面,您可以 在运行时执行此操作。 For this you should use runtime code generation (also known as Reflection.Emit ) and fetch the interface type with BindingFlags.NonPublic . 为此,您应该使用运行时代码生成(也称为 Reflection.Emit )并使用 BindingFlags.NonPublic获取接口类型。 You can read more about it here . 你可以 在这里阅读更多相关信息。

UPDATED: 更新:
As mentioned in comments below, it is impossible to inherit from a non-public interface. 如下面的评论中所述,不可能从非公共接口继承。 So unfortunately you have no solutions . 很遗憾,你没有解决方案

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM