创建实现内部接口的类型
本文关键字:类型 接口 内部 实现 创建 | 更新日期: 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
获取接口类型。你可以在这里读到更多。
更新:
正如在下面的评论中提到的,从非公共接口继承是不可能的。所以很不幸,没有解