反思或动态调度

时间:2009-11-30 11:07:35

标签: c# oop reflection dynamic-dispatch

我正在编写一个抽象文件解析器(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;
    }

3 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:2)

代码工作没有任何问题......直到有人来维护它。特别是,这种惯例需要非常仔细地记录下来,因为你的班级将如何做它的作用并不是很明显。

(顺便说一句,然而,使用Reflection会相当慢。)

最明显的方法可能是使用由子类实现的抽象基本方法bool Validate()。然后子类具有例如

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

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

也许可以让Testxxx()方法在构造函数中使用超类注册它们,这样它们就会被自动调用 - 但这样做的工作量更大,而且维护性更差。

如果确实希望使用反射执行此操作,请考虑使用属性标记Testxxx()方法并反映这些方法。然后你的代码仍然可读。

答案 2 :(得分: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();
}