代码之家  ›  专栏  ›  技术社区  ›  Ed James

方法重载:对派生类参数重载的漏斗调用

  •  5
  • Ed James  · 技术社区  · 16 年前

    好的,我试着做以下工作:

            protected bool ValidAdvert(Base item)
            {
                throw ThisIsAnAbstractClassException();
            }
    
            protected bool ValidAdvert(Derived1 item)
            {
                return ADerived1SpecificPredicate;
            }
    
            protected bool ValidAdvert(Derived2 item)
            {
                return ADerived2SpecificPredicate;
            }    

    并在将基类传递给方法时调用该方法的派生类版本。基类是抽象的,所以理论上这应该是可能的?

    在有人说要在类本身上重载方法之前,方法内部的逻辑依赖于大量不同的条件,这些条件都不相关,也没有直接与基/派生类相关(如登录状态等)。

    3 回复  |  直到 12 年前
        1
  •  6
  •   Jeff Cyr    12 年前

    如果您发现双重分派过于干扰,那么可以通过反射调用该方法并动态地解决适当的重载。

    protected bool ValidAdvert(Base item)
    {
        if (item.GetType() == typeof(Base))
            throw new ThisIsAnAbstractClassException();
    
        Type type = typeof(CurrentClass);
    
        MethodInfo method = type.GetMethod("ValidAdvert",
                                           BindingFlags.Instance | BindingFlags.NonPublic,
                                           null,
                                           new Type[] { item.GetType() },
                                           null);
        return (bool)method.Invoke(this, new object[] { item });
    }
    
    protected bool ValidAdvert(Derived1 item)
    {
        return ADerived1SpecificPredicate;
    }
    
    protected bool ValidAdvert(Derived2 item)
    {
        return ADerived2SpecificPredicate;
    }
    

    这种模式叫做 MultipleDispatch ,虽然通过反射调用方法比直接调用方法慢(如果每秒调用方法少于数百次,则不会产生开销),但它的好处是不需要像在双调度模式中那样修改类层次结构。

    当C 4.0带有动态关键字时,这将更加容易:

    protected bool ValidAdvert(Base item)
    {
        if (item.GetType() == typeof(Base))
            throw new ThisIsAnAbstractClassException();
    
        dynamic dynamicThis = this;
    
        return (bool)dynamicThis.ValidAdvert(item as dynamic);
    }
    
        2
  •  5
  •   Anton Gogolev    16 年前

    完美的使用场所 double dispatch :

    class Base
    {
        public abstract bool IsValid(IAdvertValidator validator);
    }
    
    class Derived1 : Base
    {
        public bool IsValid(IAdvertValidator validator)
        {
            return validator.ValidAdvert(this);
        }
    }
    
    class Derived2 : Base
    {
        public bool IsValid(IAdvertValidator validator)
        {
            return validator.ValidAdvert(this);
        }
    }
    
    interface IAdvertValidator
    {
        bool ValidAdvert(Derived1 d1);
        bool ValidAdvert(Derived2 d2);
    }
    
        3
  •  0
  •   tvanfosson    16 年前

    我不确定您将如何拥有一个实际上不是派生类实例的基类实例。因为基类是抽象的,所以无法实例化它。我想它会匹配任何没有特定签名的派生类,但这似乎不是您想要的。