3

我正在编写一个由两个具体解析器扩展的抽象文件解析器(C#)。两者都需要执行多次检查。目前抽象解析器中有一个验证方法,它使用反射来调用所有名称以'test'开头的方法。这样添加检查就像添加名称以“test”开头的方法一样简单。

现在最近我对反射的使用有一些评论,使用动态调度更好。我的问题是,为什么使用反射,你将如何实现它?另外我应该如何使用动态调度来解决这个问题?

    public bool Validate()
    {
        bool combinedResult = true;
        Type t = this.GetType();
        MethodInfo[] mInfos = t.GetMethods();

        foreach (MethodInfo m in mInfos)
        {
            if (m.Name.StartsWith("Check") && m.IsPublic)
            {
                combinedResult &= (bool)m.Invoke(this, null);
            }
        }
        return combinedResult;
    }
4

3 回答 3

3

您应该为此使用常规的 OOP 而不是反射。您是否让抽象类公开了一个抽象方法,如 Validate。每个解析器都必须实现它。在 Validate 中,每个解析器都会调用相关的 Check 方法来完成工作。

于 2009-11-30T11:15:00.120 回答
2

有效的代码没有任何问题……直到有人来维护它。特别是,需要非常仔细地记录这种约定,因为您的班级将如何做它所做的事情并不是很明显。

(不过,顺便说一句,为此使用反射会相当慢。)

最明显的方法可能是拥有一个bool Validate()由子类实现的抽象基方法。然后子类有例如

public override bool Validate()
{
    return TestFirst() && 
        TestSecond() &&  
        TestThird();
 }

虽然这看起来很笨重,但很明显发生了什么。它还使单元测试变得Validate()轻而易举。

也可以让Testxxx()方法在构造函数中向超类注册自己,以便自动调用它们——但这需要更多的工作并且可能更不容易维护。

如果您真的想通过反射来做到这一点,请考虑Testxxx()使用属性标记方法并对其进行反射。然后你的代码仍然可读。

于 2009-11-30T11:17:50.363 回答
0

据我了解,动态调度适用于需要根据参数类型确定要调用的方法的情况。在您的情况下,您调用没有参数的方法,所以我不确定动态调度与此有什么关系。

我喜欢你处理快速而肮脏的东西的方法。对于生产质量代码,我发现您的方法存在以下潜在问题:

  • 你不检查参数类型和返回类型,所以如果你或某人添加了一个方法string CheckWithWrongReturnType,那么你的代码就会中断。
  • 每次调用此函数时,它都会调用 GetMethods() 并遍历列表。这可能是低效的。将此列表缓存在数组中可能会更好。

为了避免反射,我会创建一个委托并让每个类返回一个委托列表。

delegate bool Validator();

bool F1() { return true;  }
bool F2() { return false; }

List<Validator> validators = new List<Validator>(F1, F2);

// 然后在主类中你可以这样做:

foreach(Validator v in validators)
{
   combinedResult &= v();
}
于 2009-11-30T11:30:48.497 回答