2017-03-18 16 views
1
public abstract class BaseClass 
{ 
    protected virtual int getValue() { return 1; } 
} 

getValueメソッドに電話します。抽象クラスでメソッドを呼び出す方法

このコードはエラーがあります。

非静的メソッドは、抽象クラスであるので、私はBaseClassのインスタンスを作成することはできません、しかし、ターゲット

が必要です。 したがって、BaseClassを拡張するダミークラスを使用しています。

class DummyClass : BaseClass { } 

typeof(BaseClass) 
    .GetMethod("getValue", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) 
    .Invoke(new DummyClass(), new object[] { }); 

私は可能な限り毎回ダミークラスを作成したくありません。

良い方法がありますか?

+5

インスタンスを作成する必要がある場合は、抽象クラスとしてマークしないでください。封印されていない限り、引き続き継承することができます。それは抽象クラスが直接的なインスタンスを作成することは決してありません。その周りに方法はありません。 – Igor

+1

あなたがこれをやっている理由は、おそらく間違ったやり方です。静的リフレクションではできない限り、抽象クラスでメソッドを実行することはできません。 –

+0

通常、私はBaseClassのインスタンスを作成しません。 しかし、私はテストでgetValueの戻り値が必要です。 抽象クラスをテスト用に標準クラスに変更する必要がありますか? – blz

答えて

1

私は、これは、生産コードをすべきではないことを他のコメントに同意するが、楽しみのうち、確かに行うことができます。

public static T CreateAbstractInstance<T>() where T : class => 
    (T)Activator.CreateInstance(
     Thread.GetDomain() 
       .DefineDynamicAssembly(new AssemblyName("DynamicAssembly"), AssemblyBuilderAccess.Run) 
       .DefineDynamicModule("DynamicModule") 
       .DefineType("DynamicType", TypeAttributes.Public | TypeAttributes.Class, typeof(T)) 
       .CreateType()); 

private static TResult AbstractInvoke<TClass, TResult>(string methodName) where TClass : class 
{ 
    var method = typeof(TClass).GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance); 

    var elegate = method.CreateDelegate(typeof(Func<BaseClass, TResult>)); 

    return (TResult)elegate.DynamicInvoke(CreateAbstractInstance<TClass>()); 
} 

private static void Main() 
{ 
    var result = AbstractInvoke<BaseClass, int>("getValue"); 

    Console.WriteLine(result); 
} 

はおそらく、コンパイラをだまして、それを呼び出すために、いくつかの方法があるにも作成することなく、インスタンスが、私はあまりにも多くなっていたVisual Studioは、他の方法の調査を続行するためにクラッシュします。式は今日の終わりにはどこにも出てこないようですが、有効なコードを生成しなければならないので、式を無効なラムダにトリックすることはできません。

シングルトンインスタンスをCreateAbstractInstanceから再利用する場合は、最初のオブジェクトが作成された後にオーバーヘッドを設定しないでください(非公開メソッドを呼び出す場合、リフレクションの使用法の横にある)。

私は、同様の答えにこれを追加するかもしれないと思った:

私はユニットテストでそれを使用してについてのコメントを注意してください。この方法であれば、あなたがで取得することはできませんのでvirtualそれが自動的にそれを上書きすることに注意してますが

var bc = new Mock<BaseClass>().Object; 
// Invoke whatever you want on `bc` with reflection or not. 

:あなたは部品番号(とまともなフレームワークのおそらく最も)を使用している場合、あなたはこれを行うことができますデフォルトは基本クラスのロジックですが、モックを設定することで解決できます。

+0

これは機能します。ありがとうございました。 – blz

+0

@blzよろしくお願いします。ちなみに、単体テストで使用しているのであれば、まともな模擬フレームワーク(Moq - > 'new Mock ().Object'を試してみました)では、ベースクラスのモックを作成することができます。具体的な実装であり、それがあなたの目的に十分に役立つかもしれません。 –

0

オープンインスタンスデリゲートを使用できます。これを試してみてください:

var method = typeof(BaseClass).GetMethod("getValue"); 
var func = (Func<BaseClass, int>) Delegate.CreateDelegate(typeof(Func<BaseClass, int>), method); 
int result = func(null); 

注:上記の手法は、メンバーの呼び出し中に隠されたthisパラメータを省略することによって動作します。これは、メソッドがインスタンスにアクセスする必要がない場合にのみ機能します。インスタンスにアクセスしようとすると、null参照例外が発生します。

+0

それは動作しません。 "オブジェクト参照がオブジェクトのインスタンスに設定されていません" – blz

+0

何か「getValue」は1を返す以上のことをします。メンバー変数にアクセスする必要がありますか? –

+0

'getValue'は' this'にアクセスできません。 – blz

関連する問題