反射或动态调度

发布于 2024-08-12 20:40:59 字数 665 浏览 5 评论 0原文

我正在编写一个抽象文件解析器(C#),它由两个具体解析器扩展。两者都需要执行多项检查。目前抽象解析器中有一个 validate 方法,它使用反射来调用名称以 '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;
    }

I'm writing a abstract file parser (C#) which is extended by two concrete parsers. Both need to perform several checks. Currently there is a validate method in the abstract parser, which uses reflection to call all methods with a name starting with 'test'. That way adding checks is as easy as adding a method with a name that starts with 'test'.

Now recently I've had some comments about the use of reflection and it being better to use dynamic dispatching. My question to you is, why not use reflection and how would you implement this? Also how should I use dynamic dispatch to solve this problem?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

口干舌燥 2024-08-19 20:40:59

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

You should use regular OOP and not reflection for this. Have you abstract class expose an abstract method like Validate. Each parser will have to implement it. In the Validate, each parser will call the revelent Check methods to do the work.

落花浅忆 2024-08-19 20:40:59

有效的代码没有任何问题......直到有人来维护它。特别是,这种约定需要非常仔细地记录下来,因为你的类将如何做它所做的事情并不是立即显而易见的。

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

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

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

虽然这看起来很庞大,但发生的事情立即显而易见。它还使 Validate() 的单元测试变得轻而易举。

也可以让 Testxxx() 方法在构造函数中向超类注册自身,以便自动调用它们 - 但这会增加工作量,而且可能不太容易维护。

如果您确实想通过反射来完成此操作,请考虑使用属性标记 Testxxx() 方法,然后对这些方法进行反射。然后你的代码仍然可读。

There's nothing wrong with code that works... until someone comes to maintain it. In particular, this kind of convention would need to be documented quite carefully as it's not immediately obvious how your class will do what it does.

(As an aside, however, using Reflection for this will be rather slow.)

The most obvious way might be to have an abstract base method bool Validate() that is implemented by the subclasses. The subclasses then have e.g.

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

While this looks bulky it's immediately obvious what's going on. It also makes unit testing of Validate() a breeze.

It might also be possible to have the Testxxx() methods register themselves with the superclass in the constructor so they are called automatically - but that's more work and probably less maintainable.

If you really want to do this with reflection, consider marking the Testxxx() methods with attributes and reflecting on those instead. Then your code remains readable.

新人笑 2024-08-19 20:40:59

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

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

  • 您不检查参数类型和返回类型,因此如果您或某人添加了方法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();
}

As far as I understand, dynamic dispatch is for the cases when you need to determine the method to call based on the type of its arguments. In your case, you call methods with no arguments, so I am not sure what dynamic dispatch has to do with this.

I like your approach for quick-and-dirty stuff. For production-quality code, I see the following potential problems with your approach:

  • you don't check for argument types and return types, so if you or someone adds a method string CheckWithWrongReturnType then your code breaks.
  • every time you call this function it calls GetMethods() and goes through the list. This is probably inefficient. Might be better to cache this list in an array.

To avoid reflection, I would create a delegate and make each class return a list of delegates.

delegate bool Validator();

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

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

// then in the main class you can do this:

foreach(Validator v in validators)
{
   combinedResult &= v();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文