【问题标题】:Better way to call overloaded functions with more-derived parameters, passing in less-derived types使用更多派生参数调用重载函数的更好方法,传入更少派生类型
【发布时间】:2014-09-17 02:38:03
【问题描述】:

我有 16 个带有两个参数的方法,两个参数中的每一个都可以是“插入”或“删除”,它们都实现了 IFragment。我也有四个这样的辅助函数:

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

它只是确定实际类型并调用适当的重载。有没有更清洁的方法来做到这一点?换一种说法,我可以用衍生较少类型的对象调用衍生较多的函数重载吗?

编辑: IntroduceAntecedent 重载的签名

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)

【问题讨论】:

  • 您能否也分享一下 IntroduceAntecedent 的外观。这可以帮助您真正了解您要做什么并简化它。
  • 我已经添加了签名。
  • 如果我理解正确,您应该能够将 4 个 IntroduceAntecedent 方法定义为 Extension Methods,并提供签名,然后简单地调用它们得到正确的调用

标签: c# inheritance overloading


【解决方案1】:

我已经实现了 DynamicDispatcher.cs 来满足这个需求。

它使用反射和堆栈跟踪(构造中的单个)来生成按参数类型的重载树。它处理基类和实现接口的双向转换。

由于它是一个更大项目的一部分并且没有任何文档,这里是一个使用示例 (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);
    }

【讨论】:

  • 我宁愿坚持最初的尝试也不愿这样做,尽管根本问题似乎是您的课程的设计问题。
  • 请您详细说明一下好吗? :)
  • 三种更简单的方法来实现运行时绑定,就像使用动态关键字一样。我认为(只是我的观点)在您的情况下根本不需要运行时绑定,只是接口(或更专业的接口)应该提供所有必需的功能来实现 IntroduceAntecedent 所做的任何事情。
【解决方案2】:

首先,您不能使用“较少派生”的对象调用方法,因为您正在调用的方法正在等待此类型的最低要求。

对于这类问题,我认为最好为该函数使用不同的名称。 “IntroduceAntecedent”应该与“IntroduceAntecedent_DelDel”以及所有其他 3 个组合一起存在。这显然是我自己的观点,但你的做法似乎符合你的预期。

【讨论】:

    猜你喜欢
    • 2017-07-15
    • 1970-01-01
    • 2015-12-30
    • 1970-01-01
    • 2014-10-31
    • 1970-01-01
    • 2021-05-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多