2011-12-22 26 views
9

内部インターフェイスIInternalInterfaceを宣言するアセンブリがあるとします。私はこのアセンブリのコードにアクセスすることはできず、私はそれを変更することはできません。 IInternalInterfaceの独自の実装を作成するにはどうすればよいですか?内部インターフェイスを実装する型を作成します

私はこれがなぜ必要なのですか:アセンブリにはIInternalInterfaceの実装者のリストを含むクラスが含まれています。私の目標はそこに独自の実装を追加することです。

答えて

4

IInternalInterfaceの独自の実装を作成するにはどうすればよいですか?

簡単な回答:できません。アセンブリの作成者がこのインターフェイスにinternalとマークすることにした場合、他のアセンブリのコードでこのインターフェイスを使用したくないということを意味します。

+3

ああ、そうすることができます。反射を使用してください。しかし、龍には注意してください。 –

+5

@ noah1989では、Reflection.Emitを使用して内部インターフェイスを実装するクラスを生成することはできません。この動的クラスをロードしようとすると、実行時にTypeLoadException例外が発生します。 –

+0

実際には、アセンブリから '...'を入力してください '...'は はアクセスできないインターフェイスを実装しようとしています。 –

0

あなたが一方からコンパイル時に

このインタフェースを実装することはできません、あなたがそれを行うことができ、限り、あなたがソースコードにアクセス全くないよう [InternalsVisibleTo()]属性を追加しますが、可能性があり実行時にこのためには、ランタイムコード生成(Reflection.Emitとも呼ばれます)を使用し、BindingFlags.NonPublicでインターフェイスタイプを取得する必要があります。あなたはそれについてもっと読むことができますhere。 UPDATED


以下のコメントで述べたように、非パブリックインターフェイスを継承することは不可能です。だから、残念ながらの解決策はありません

+0

私はそれが動作すると思ったが、それはできません(http://stackoverflow.com/questions/4350363/reflectiontypeloadexception-type-is-attempting-to-implement-an-inaccessible-int)。 –

+0

ありがとうございます。私は私の答えを更新しました。これについて知りませんでした。 –

0

アセンブリバージョンのリダイレクトまたはタイプリダイレクトを使用して、インターフェイス宣言をコントロールの下にあるアセンブリに「移動」し、実装を公開することもできます。

しかし、Darin氏によると、このアプローチについて二重に考えてください。よりきれいになるライブラリ機能を拡張するための意図された方法があるかもしれません...

+0

バージョンリダイレクトまたはタイプリダイレクトとは何ですか? –

+0

@全体:Googleは純粋な魔法です!ここ:http://msdn.microsoft.com/en-us/library/7wd6ex19(v=vs.71).aspxおよびhttp://msdn.microsoft.com/en-us/library/ms404275.aspx –

+0

@ noah1989アセンブリのコードにアクセスする必要があります。 –

7

リモートプロキシを使用することは可能です。
私の答えは簡単なスケッチであり、さらに改善する必要があるかもしれないことに注意してください。

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

それは本当に便利だったが、いくつかのビットを逃したように私は@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(); 
    } 
} 

するか、我々がアクセス権を持っていない場合反射でそれを割り当てます。それを検証するために、我々は、内部インターフェイスを含むアセンブリでこれを行うことができます。

関連する問題