反射还是动态分派

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;
    }
3个回答

3
你应该使用常规的面向对象编程,而不是反射。让你的抽象类公开一个名为 Validate 的抽象方法,每个解析器都必须去实现它。在 Validate 方法里,每个解析器将调用相应的 Check 方法来完成工作。

最好坚持使用标准的面向对象编程实践。反射是非常有用的,但不如标准函数调用高效。 - Zoidberg
另外,当涉及到抽象语法树(AST)时(如果您正在使用它们),请查看访问者模式。 - Zoidberg

2

代码能够运行并没有问题,但是当有人来维护它时就会出现问题。特别是这种惯例需要被仔细记录,因为不清楚你的类将如何执行所需的操作。

(顺便说一句,使用反射会比较慢。)

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

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

虽然看起来有些臃肿,但显而易见正在发生什么。这也使得Validate()单元测试变得轻而易举。
可能还可以在构造函数中让Testxxx()方法自动向超类注册,这样它们就会被自动调用——但那需要更多的工作,而且可能不太可维护。
如果您真的想使用反射来做到这一点,请考虑使用属性标记标记Testxxx()方法,然后对其进行反射。这样,您的代码仍然易读。

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();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接