2012-04-12 14 views
9

私はASP.NET MVC3のためのソースコードを読んでいる、と私はControllerBaseためのコードの中に次のように出くわした:このコードのポイントは何ですか?

public interface IController 
{ 
    void Excecute(RequestContext requestContext); 
} 


public abstract class ControllerBase : IController 
{ 

    protected virtual void Execute(RequestContext requestContext) 
    { 
     if (requestContext == null) 
     { 
      throw new ArgumentNullException("requestContext"); 
     } 
     if (requestContext.HttpContext == null) 
     { 
      throw new ArgumentException(MvcResources.ControllerBase_CannotExecuteWithNullHttpContext, "requestContext"); 
     } 

     VerifyExecuteCalledOnce(); 
     Initialize(requestContext); 

     using (ScopeStorage.CreateTransientScope()) 
     { 
      ExecuteCore(); 
     } 
    } 

    void IController.Execute(RequestContext requestContext) 
    { 
     Execute(requestContext); 
    } 
} 

ControllerBaseがExecuteの実装を提供しますが、それが提供して何かを持っています.. IController.Executeの定義?

なぜこれが行われ、何が達成されますか?それは目的を果たさないようです。

+0

を使用すると、仮想 'Execute'をオーバーライドする場合は、明示的に' IController.Execute'はまだベースの実装を実行しますか? – Joe

+0

@Joe No.オーバーライドされた仮想Executeが存在すれば実行します。 – Scott

+0

だから、そのメソッドを 'protected'にして' public'にするのはちょうどハックです。 – Joe

答えて

6

このコードを使用すると、Executeメソッドをオーバーライドすることができます。

通常実装されているインターフェイスメソッドはパブリックであり、派生クラスでオーバーライドすることはできないため、デフォルトではIControllerインターフェイスから新しいExecuteメソッドを作成することはできません。保護された仮想技術に対するこのインタフェース)。保護された仮想メソッド(明示的に実装されたインターフェイスメソッドから呼び出す)を作成することにより、派生クラスはインターフェイス実装を破ることなくExecuteメソッドをオーバーライドできます。

私はここでこのことについて優れた記事を見つけました: C# Overriding Interface Methods in Subclasses

+0

基本的に、私がサブクラスで変更したいインターフェイスを介していくつかの機能を公開したい場合は、このパターンを使用することができます。 –

+0

なぜ 'public virtual Execute(RequestContext requestContext) 'よりもこのデザインパターンを好むでしょうか? – Scott

+2

@Scott public virtualを使用すると、IControllerインターフェイスへの参照なしに、このクラスの外部からアクセスできるようになります。それは一般公開されるだろう。 protectedを使用すると、IControllerインターフェイスへの明示的な参照がない限り、ControllerBaseクラスおよびその子孫の内部にメソッドが保持されます。だから、より良い保護され、非常に意図的にアクセスされた場合にのみ使用されます。 – BenSwayne

2

MSDN Documentationによると、明示的なインターフェイスメンバ実装の目的の1つは次のとおりです。 "明示的なインターフェイスメンバ実装はクラスまたは構造体インスタンスからアクセスできないため、インターフェイスの実装をクラスまたは構造体のパブリックインターフェイスから除外できます。クラスまたは構造体が、そのクラスまたは構造体のコンシューマにとって関心のない内部インタフェースを実装する場合に、特に有用です。

上記の私の解釈が正しい場合、タイプControllerBaseの変数は、保護されているのでExecuteを呼び出すために使用することはできません。変数の型はIControllerでなければなりません。私はこれがコンストラクトの意図であるかどうかはわかりませんが、これが理由であると感じます。

関連するテストでは、を呼び出す前に、ControllerBaseの変数をIControllerに明示的にキャストします。

+0

おそらく、「外部」からのExecuteコールをあいまいにするのは単なる素晴らしい方法です。 – Scott

+1

@Scottこれは、責任の分離を強制するために使用されていると思います。 'ControllerBase'リファレンスを保持していれば、それを実行するつもりはありません。 'IController'を保持しているのであれば、それを実行するだけです。 – vhallac

1

一見、このデザインパターンは目的を果たさないようです。ただし、ControllerBaseクラスは、後で改ざんを行わずにIControllerインターフェイスの実装を行う機会を提供します。 base.Execute()を呼び出す継承クラスに依存しないため、変更が実行されることが保証されます。これは将来のコンテキストやセキュリティを管理するために使用される可能性がありますか?

多分、開発者はインタフェースのオーバーライド可能な実装との論理的分離を保つのが好きかもしれません。

関連する問題