Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
197 views
in Technique[技术] by (71.8m points)

c# - how to improve this method using polymorphism+overloading so as to reduce IS (type check)?

For example

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

where InheritedA, and InheritedB are its inherited classes. In fact, there are more Inherited classes, and the Add returns different results based on the order and types of its operand.

I am thinking of rewriting it using Polymorphism and overloading, however, it becomes rather complicated, I have to introduce an helper method to resolve the type of either end.

e.g.

InheritedA myA()

{
    public override int Add(BaseClass next)
    {
        return next.AddTo(this);
    }
}

Now I have to put AddTo into BaseClass, and override it in inherited class as well.

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

Is there a better way of doing it?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The pattern you are implementing is called double virtual dispatch.

A single virtual dispatch chooses which method to call on the basis of the run-time type of the receiver and the compile time type of the arguments. This is a traditional virtual dispatch:

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

Which method is called? B.M(Tiger) and D.M(Tiger) are not chosen; we reject them based on the compile time type of the argument, which is Animal. But we choose whether to call B.M(Animal) or D.M(Animal) at runtime based on whether whatever is new B() or new D().

Double virtual dispatch chooses which method to call based on the runtime types of two things. If C# supported double virtual dispatch, which it does not, then the runtime dispatch would go to B.M(Tiger) or D.M(Tiger) even though the compile-time type of the argument is Animal.

C# 4 does however support dynamic dispatch. If you say

dynamic b = whatever;
dynamic a = new Tiger();
b.M(a);

Then the analysis of M will be done entirely at runtime using the runtime types of b and a. This is significantly slower, but it does work.

Alternatively, if you want to do double virtual dispatch and get as much analysis done at compile time as possible then the standard way to do that is to implement the Visitor Pattern, which you can look up on the internet easily.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...