Better way to call overloaded functions with more-derived parameters, passing in less-derived types

一曲冷凌霜 提交于 2021-02-17 05:12:50

问题


I have 16 methods that take two parameters, and each of the two parameters can be either an 'Insertion' or a 'Deletion', both of which implement IFragment. I also have four helper functions like this:

    static IFragment[] IntroduceAntecedent(IFragment on, IFragment item) {
        bool onIsInsertion = on is Insertion;
        bool itemIsInsertion = item is Insertion;
        if (onIsInsertion) {
            if (itemIsInsertion) {
                return IntroduceAntecedent((Insertion) on, (Insertion) item);
            } else {
                return IntroduceAntecedent((Insertion) on, (Deletion) item);
            }
        }
        else {
            if (itemIsInsertion) {
                return IntroduceAntecedent((Deletion)on, (Insertion)item);
            } else {
                return IntroduceAntecedent((Deletion)on, (Deletion)item);
            }
        }
    }

It does nothing more than determine the actual types and call the appropriate overload. Is there a cleaner way to do this? Worded another way, can I call more-derived overload of a function with objects that are of a less-derived type?

Edit: The signatures of the IntroduceAntecedent overloads

static IStringTransform[] IntroduceAntecedent(Deletion lhs, Deletion rhs)
static IStringTransform[] IntroduceAntecedent(Deletion lhs, Insertion rhs)
static IStringTransform[] IntroduceAntecedent(Insertion lhs, Deletion rhs)
static IStringTransform[] IntroduceAntecedent(Insertion lhs, Insertion rhs)

回答1:


I've implemented DynamicDispatcher.cs which fulfills this need.

It uses reflection and a stack trace (a single one on construction) to generate a tree of overloads by parameter types. It handles bidirectional casting on base classes and implemented interfaces.

Since it's part of a larger project and doesn't have any documentation, here's an example use (from the same project):

    public static void DeleteTreeNodeChild(BehaviorTree.Choice parentNode, BehaviorTree.Node childNode) {
        parentNode.Children.Remove(childNode);
    }

    public static void DeleteTreeNodeChild(BehaviorTree.Optional parentNode, BehaviorTree.Node childNode) {
        Debug.Assert(parentNode.Child == childNode);
        parentNode.Child = null;
    }

    public static void DeleteTreeNodeChild(BehaviorTree.Repetition parentNode, BehaviorTree.Node childNode) {
        Debug.Assert(parentNode.Child == childNode);
        parentNode.Child = null;
    }

    public static void DeleteTreeNodeChild(BehaviorTree.Sequence parentNode, BehaviorTree.Node childNode) {
        parentNode.Children.Remove(childNode);
    }

    private static DynamicDispatcher _deleteTreeNodeChildDynamicDispatcher;
    public static void DeleteTreeNodeChild(BehaviorTree.Node parentNode, BehaviorTree.Node childNode) {
        if (_deleteTreeNodeChildDynamicDispatcher == null) {
            _deleteTreeNodeChildDynamicDispatcher = new DynamicDispatcher();
        }
        _deleteTreeNodeChildDynamicDispatcher.Dispatch<Object>(null, parentNode, childNode);
    }



回答2:


First of all, you can't call a method with objects that are "less derived" since the method you are calling is waiting for a minimum requirements from this type.

For this type of problem, I think it's better just using different names for that function. "IntroduceAntecedent" should exist along with "IntroduceAntecedent_DelDel" and all 3 other combinaisons. That's clearly my own opinion, but The way you did it seems ok for what you would expect it to do.



来源:https://stackoverflow.com/questions/25881394/better-way-to-call-overloaded-functions-with-more-derived-parameters-passing-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!