创建实现内部接口的类型

时间:2022-03-31 09:42:09

Suppose I have assembly that declares internal interface 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的程序集。我无法访问此程序集的代码,我无法更改它。如何创建自己的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实现者列表的类,我的目标是在那里添加我自己的实现。

6 个解决方案

#1


4  

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.

简单回答:你做不到。如果程序集的作者决定用内部标记此接口,则意味着他们不希望其他程序集中的代码使用此接口。

#2


7  

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

#3


1  

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正在尝试实现一个不可访问的接口

#4


1  

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. 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.

如果我们没有访问权限,请为其分配反射。

#5


0  

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...

但正如达林所说,一定要仔细考虑这种方法。可能有一种扩展库功能的预期方法会更清晰......

#6


0  

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. You can read more about it here.

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

UPDATED:
As mentioned in comments below, it is impossible to inherit from a non-public interface. So unfortunately you have no solutions.

更新:如下面的评论所述,不可能从非公共接口继承。很遗憾,你没有解决方案。

#1


4  

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.

简单回答:你做不到。如果程序集的作者决定用内部标记此接口,则意味着他们不希望其他程序集中的代码使用此接口。

#2


7  

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

#3


1  

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正在尝试实现一个不可访问的接口

#4


1  

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. 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.

如果我们没有访问权限,请为其分配反射。

#5


0  

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...

但正如达林所说,一定要仔细考虑这种方法。可能有一种扩展库功能的预期方法会更清晰......

#6


0  

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. You can read more about it here.

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

UPDATED:
As mentioned in comments below, it is impossible to inherit from a non-public interface. So unfortunately you have no solutions.

更新:如下面的评论所述,不可能从非公共接口继承。很遗憾,你没有解决方案。