0

私はテストコンポーネントをセットアップし、それを汎用的に維持しようとしています。一般的なVisitorクラスを使用したいのですが、子孫クラスの使用についてはよくわかりません。

例:

public interface Interface_Test_Case
{
  void execute();
  void accept(Interface_Test_Visitor v);
}


public interface Interface_Test_Visitor
{
  void visit(Interface_Test_Case tc);
}


public interface Interface_Read_Test_Case
  : Interface_Test_Case
{
  uint read_value();
}


public class USB_Read_Test
  : Interface_Read_Test_Case
{
  void execute()
  { Console.WriteLine("Executing USB Read Test Case."); }

  void accept(Interface_Test_Visitor v)
  { Console.WriteLine("Accepting visitor."); }

  uint read_value()
  {
    Console.WriteLine("Reading value from USB");
    return 0;
  }
}


public class USB_Read_Visitor
  : Interface_Test_Visitor
{
  void visit(Interface_Test_Case tc)
  { Console.WriteLine("Not supported Test Case."); }

  void visit(Interface_Read_Test_Case rtc)
  { Console.WriteLine("Not supported Read Test Case."); }

  void visit(USB_Read_Test urt)
  { Console.WriteLine("Yay, visiting USB Read Test case."); }
}

// Code fragment
  USB_Read_Test test_case;
  USB_Read_Visitor visitor;
  test_case.accept(visitor);

C#コンパイラがUSB_Read_Visitorコードフラグメントによって実行されるメソッドを決定するために使用するルールは何ですか?

テストコンポーネントの依存関係を除外しようとしています。残念ながら、現在のVisitorクラスにはvisit、テストコンポーネントに関連しないクラスのメソッドが含まれています。私は不可能を達成しようとしていますか?

4

3 に答える 3

1

インターフェース全体とVisitingの関連する実装を定義する代わりに、アクション(または、Visitorに実行させたい内容に応じてPredicateまたはFunc)を受け入れるVisitメソッドを定義します。

class TestCase
{
    public void Visit(Action<T> action, T val) 
    {
        action(val);
    }

}

var tc = new TestCase();
uint some_val = 3;
tc.Visit((Action) (val) => Console.WriteLine("Val " + val));

あなたが何をしようとしているのか完全にはわかりませんが、関数を受け取るメソッドを定義することで、それらすべてのインターフェースを定義する必要がなくなります。

于 2011-03-12T00:51:38.507 に答える
1

あなたのaccept()メソッドは実際にはどのvisit()メソッドも呼び出さないので、どれも呼び出しません。:)

ただし、次のように呼び出した場合:

void accept(Interface_Test_Visitor v)
{
    Console.WriteLine("Accepting visitor.");
    v.Visit(this); // lets invoke it this time
}

コンパイラは、それが最初に、、次に、thisのインスタンスとして認識されます。最初に最も直接的なオーバーロード(または暗黙の変換を使用できるもの)を選択し、次にオーバーロードに適合する適切なタイプが見つかるまで継承チェーンをたどります。したがって、この場合は、を呼び出します。次をキャストすることで、この動作をオーバーライドできます。USB_Read_TestInterface_Read_Test_CaseInterface_Test_Casevisit(USB_Read_Test)

v.Visit((Interface_Read_Test_Case)this); // argument is an instance of Interface_Read_Test_Case
v.Visit((Interface_Test_Case)this);      // argument is an instance of Interface_Test_Case

ただし、クラスが複数のインターフェイスを実装している場合、各インターフェイスにはオーバーロードがありますが、クラスにはオーバーロードがない場合は、解決する必要のあるあいまいなエラーが発生します。

例えば、

interface IX { }
interface IY { }
class Class : IX, IY { }

void Call(IX _) { }
void Call(IY _) { }
// no Call(Class _) method

var c = new Class();
Call(c); // error: ambiguous call
Call((IX)c); // not ambiguous

詳細については、メソッドの解決順序とわずかに関連するC#:オーバーロードされたメソッドへのnullの受け渡し-どのメソッドが呼び出されるかを参照してください。

于 2011-03-12T00:42:33.270 に答える
0

コメントが言うように、acceptはvisitメソッドを呼び出さないので、私はあなたが何を意味していると思うかに基づいて答えます...パラメータとして渡されたオブジェクトの宣言されたタイプに基づいて考えたでしょうか?

USB_Read_Test obj1 = new USB_Read_Test();
Interface_Read_Test_Case obj2 = new USB_Read_Test();

両方をパラメーターとして呼び出すと、visit(USB_Read_Test urt)obj1とvisit(Interface_Read_Test_Case rtc)obj2になります。

于 2011-03-12T00:29:43.073 に答える