【问题标题】:Create type that implements internal interface创建实现内部接口的类型
【发布时间】:2011-12-22 15:57:45
【问题描述】:

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

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

【问题讨论】:

    标签: c# .net


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      如何创建自己的 IInternalInterface 实现?

      简单的答案:你不能。如果程序集的作者决定用internal 标记这个接口,这意味着他们不希望其他程序集的代码使用这个接口。

      【讨论】:

      • 哦,是的,你可以.. 使用 Reflection.Emit .. 但要小心龙。
      • @noah1989,您不能使用 Reflection.Emit 生成实现内部接口的类。当您尝试加载此动态类时,您将在运行时收到 TypeLoadException 异常。
      • 确实..“来自程序集 '...' 的类型 '...' 正在尝试实现一个不可访问的接口。”
      • 我需要一个复杂的答案:)
      • @Orsol,没有。如果你不能touch包含这个接口的程序集的源代码,你会非常高兴。
      【解决方案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();
          }
      }
      

      如果我们无权访问,则将其分配给 reflection

      【讨论】:

        【解决方案4】:

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

        但正如达林所说,请务必三思而后行。可能有一种扩展库功能的预期方法会更干净......

        【讨论】:

        • 什么是版本重定向或类型重定向?
        • @Orsol:您可以制作一个“假”程序集,将所有内容重定向到原始程序集,但添加您的接口实现。不确定这是否有效,但即使有效,它也是一个非常肮脏的黑客攻击。
        • 难道不能只将接口重定向到新创建的程序集并在那里公开吗?但如前所述,欢迎来到黑暗面;)
        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

          您可以添加[InternalsVisibleTo()] 属性,但就您无法访问源代码而言,您无法在编译时实现此接口

          另一方面,您可以在运行时进行。为此,您应该使用运行时代码生成(也称为Reflection.Emit)并使用@987654325 获取接口类型@。你可以阅读更多关于它的信息here

          更新:
          正如下面的 cmets 中提到的,不可能从非公共接口继承。所以很遗憾,您没有解决方案

          【讨论】:

          • 不。我认为这可行,但它doesn't.
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-05-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-01-04
          • 1970-01-01
          相关资源
          最近更新 更多