0

我正在设置一个测试组件并试图保持它的通用性。我想使用通用的访问者类,但不确定是否使用后代类。

例子:

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代码片段将执行哪些方法?

我正在尝试排除我的测试组件的依赖关系。不幸的是,我当前的访问者类包含visit与测试组件无关的类的方法。我在努力实现不可能吗?

4

3 回答 3

1

由于您的accept()方法实际上并未调用任何visit()方法,因此没有。:)

但是,如果您将其调用为:

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

编译器会看到thisis first 作为USB_Read_Test, then Interface_Read_Test_Case, then的实例Interface_Test_Case。它将首先选择最直接的重载(或可以使用隐式转换的重载),然后沿着继承链向下走,直到找到适合重载的合适类型。所以在这种情况下,它会调用visit(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 回答
1

与其为 Visiting 定义整个接口和相关实现,不如定义一个接受 Action(或 Predicate 或 Func,具体取决于您希望 Visitor 做什么)的 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));

尽管我并不完全清楚您要做什么,但定义一个采用 Function 的方法可以消除定义所有这些接口的必要性。

于 2011-03-12T00:51:38.507 回答
0

正如评论所说,accept 不会调用任何访问方法,所以我根据我认为你的意思来回答......我会认为它是基于作为参数传入的对象的声明类型?

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 回答