创建实现内部接口的类型

时间:2011-12-22 15:57:46

标签: c# .net

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

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

6 个答案:

答案 0 :(得分:9)

可以使用远程代理 请注意,我的答案只是一个快速草图,可能需要进一步改进。

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

答案 1 :(得分:3)

  

如何创建自己的IInternalInterface实现?

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

答案 2 :(得分:3)

我会延长@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();
    }
}

如果我们无法访问,请使用反射进行分配。

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

恐怕这是不可能的。即使您设法使用Reflection.Emit创建一个实现该接口的类,您也将无法使用它,因为您将获得ReflectionTypeLoadException: Type is attempting to implement an inaccessible interface

答案 5 :(得分:-1)

您可以添加[InternalsVisibleTo()]属性,但只要您无法访问源代码,就无法在编译时实现此接口 < / p>

另一方面,您可以在运行时执行此操作。为此,您应该使用运行时代码生成(也称为Reflection.Emit)并获取接口类型BindingFlags.NonPublic。您可以阅读更多相关信息here

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