首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用polymorphism+overloading改进此方法,以减少IS (类型检查)?

如何使用polymorphism+overloading改进此方法,以减少IS (类型检查)?
EN

Stack Overflow用户
提问于 2012-03-27 23:28:39
回答 2查看 280关注 0票数 6

例如

代码语言:javascript
复制
BaseClass MyBase()
{
    public int Add(BaseClass next)
    {
        if (this is InheritedA && next is InheritedA)
            return 1;
        else if (this is InheritedA && next is InheritedB)
            return 2;
        else if (this is InheritedB && next is InheritedA)
            return 3;
        else if (this is InheritedB && next is InheritedB)
            return 4;      
     }
}

其中,InheritedAInheritedB是它的继承类。实际上,有更多的继承类,并且Add根据其操作数的顺序和类型返回不同的结果。

我正在考虑使用多态和重载重写它,然而,它变得相当复杂,我必须引入一个辅助方法来解析两端的类型。

例如:

代码语言:javascript
复制
InheritedA myA()
{
    public override int Add(BaseClass next)
    {
        return next.AddTo(this);
    }
}

现在,我必须将AddTo放入BaseClass中,并在继承的类中覆盖它。

代码语言:javascript
复制
InheritedA myA()
{
    public override int AddTo(InheritedA next) { return 1; }
    public override int AddTo(InheritedB next) { return 3; }
}

BaseClass myBase()
{
    public abstract int Add(BaseClass next);
    public abstract int AddTo(InheritedA next);
    public abstract int AddTo(InheritedB next);
}

有没有更好的方法呢?

EN

回答 2

Stack Overflow用户

发布于 2012-03-28 01:43:44

您正在实现的模式称为双重虚拟分派。

单个虚拟调度根据接收方的运行时类型和参数的编译时类型选择要调用的方法。这是传统的虚拟派单:

代码语言:javascript
复制
abstract class Animal {}
class Tiger : Animal {}
class Giraffe : Animal {} 
class B
{
    public virtual void M(Tiger x) {}
    public virtual void M(Animal x) {}
}
class D : B
{
    public override void M(Tiger x) {}
    public override void M(Animal x) {}
}
...
B b = whatever;
Animal a = new Tiger();
b.M(a);

哪个方法被调用?没有选择B.M(Tiger)D.M(Tiger);我们根据参数的编译时类型拒绝它们,即Animal。但是我们可以根据whatevernew B()还是new D()来选择在运行时调用whatever还是D.M(Animal)

Double virtual dispatch根据两件事的运行时类型选择要调用的方法。如果C#支持双重虚拟分派,那么运行时分派将转到B.M(Tiger)D.M(Tiger),即使参数的编译时类型是Animal。

但是,C# 4确实支持动态分派。如果你说

代码语言:javascript
复制
dynamic b = whatever;
dynamic a = new Tiger();
b.M(a);

然后,将在运行时使用ba的运行时类型完全完成对M的分析。这要慢得多,但它确实起作用了。

或者,如果您希望执行双重虚拟分派并在编译时完成尽可能多的分析,那么实现这一点的标准方法是实现访问者模式,您可以很容易地在internet上查找该模式。

票数 9
EN

Stack Overflow用户

发布于 2012-03-28 00:11:16

正如注释中所建议的,如果您能够为每个派生函数分配一个常量值,那么您可以构建一个比我在这里描述的更干净的实现,只需拥有一个用于添加的名为Value或类似的虚拟属性。

假设这不是一个选项,您可能希望考虑在基类级别预先计算结果,以描述您为每个组合分配的值。随着类集合的增长,这可能会崩溃并变得容易出错和单调乏味,所以我建议只有在您希望维护非常小的集合时才考虑这一点。

在我的基本示例中,我使用字典来保存集合并对组合进行硬编码。从你的评论来看,算术的基本规则似乎都不适用,所以我在这里省略了它们作为约束。如果结果值没有实际意义,而您只是在递增它,那么您可以考虑使用反射来提取派生类并考虑每种组合来构建结果集。

代码语言:javascript
复制
public class BaseClass
{
  private static readonly Dictionary<int, int> addResults = new Dictionary<int, int>();

  static BaseClass()
  {
    addResults.Add(CreateKey(typeof(ChildA), typeof(ChildA)), 1);
    addResults.Add(CreateKey(typeof(ChildA), typeof(ChildB)), 2);
    addResults.Add(CreateKey(typeof(ChildB), typeof(ChildA)), 3);
    addResults.Add(CreateKey(typeof(ChildB), typeof(ChildB)), 4);
  }

  public static int CreateKey(Type a, Type b)
  {
    return (String.Concat(a.Name, b.Name).GetHashCode());
  }

  public int Add(BaseClass next)
  {
    var result = default(int);

    if (!addResults.TryGetValue(CreateKey(this.GetType(), next.GetType()), out result))
    {
      throw new ArgumentOutOfRangeException("Unknown operand combination");
    }

    return result;
  }
}

public class ChildA : BaseClass {}
public class ChildB : BaseClass {}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9892660

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档