【发布时间】:2011-12-22 15:57:45
【问题描述】:
假设我有声明内部接口IInternalInterface 的程序集。我无权访问此程序集的代码,也无法更改它。
如何创建自己的 IInternalInterface 实现?
为什么我需要这个:程序集包含具有IInternalInterface 实现者列表的类,我的目标是在那里添加我自己的实现。
【问题讨论】:
假设我有声明内部接口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();
}
}
如果我们无权访问,则将其分配给 reflection。
【讨论】:
您还可以使用程序集版本重定向或类型重定向将接口声明“移动”到您控制下的程序集并公开您的实现。
但正如达林所说,请务必三思而后行。可能有一种扩展库功能的预期方法会更干净......
【讨论】:
恐怕这是不可能的。即使您设法使用 Reflection.Emit 创建了一个实现该接口的类,您也无法使用它,因为您会得到一个 ReflectionTypeLoadException: Type is attempting to implement an inaccessible interface
【讨论】: