C # polymorphism vs. New keyword

Source: Internet
Author: User

1. How do you usually use polymorphism?

Suppose I have a class with a Printstatus method that prints the current state of the instance, and I want the class's derived classes to have a Printstatus method that prints the current state of their instance. Then I would like to express my wish:

Code #01

Class Base
{
public virtual void Printstatus ()
{
Console.WriteLine ("Public virtual void Printstatus () in Base");
}
}

So I can write a method like this:

Code #02

public void Displaystatusof (base[] bs)
{
foreach (Base b in BS)
{
B.printstatus ();
}
}

BS may contain derived classes of different Base, but we can ignore these "personalities" and use a uniform way to deal with something. In. NET 2.0, the XmlReader Create has a version that:

public static XmlReader Create (Stream input);

You can pass any available "stream" to Create, such as a "stream" from a file (FileStream), a "stream" from memory (MemoryStream), or a "stream" (NetworkStream) from the network. While each of the "flow" work details are different, we use a unified approach to these "flows".

2. If someone does not abide by the promise ...

Displaystatusof implies the assumption that if an instance of a derived class exists in BS, the derived class should override the Printstatus and, of course, must add the Override keyword:

Code #03

Class Derived1:base
{
public override void Printstatus ()
{
Console.WriteLine ("public override void Printstatus () in Derived1");
}
}

You can think of it as a promise, an agreement, until someone sinks in.

Code #04

Class Derived2:base
{
Public new void Printstatus ()
{
Console.WriteLine ("Public new void Printstatus () in Derived2");
}
}

Suppose we have such an array://Code #05

Base[] bs = new base[]
{
New Base (),
New Derived1 (),
New Derived2 ()
};

Pass it to displaystatusof, then the output is:

Output #01

public virtual void Printstatus () in Base
public override void Printstatus () in Derived1
public virtual void Printstatus () in Base

It is easy to see from the output that Derived2 did not do as we expected. But you don't have to be surprised, because Derived2 's designers don't "obey the rules".

3. NEW: Seal spell

New seems to give people the feeling that its users like to break the conventions of others, however, if used properly, new can compensate for the "sighted" of the base class Designer. In Creating a Data Bound ListView Control, Rockford Lhotka demonstrates how to seal the original listview.columns and make the return datacolumnheadercollect of the self-added Ion's Columns instead.

From the Output #01 we can see that new just seals up the base.printstatus instead of destroying it, and you can remove the seal and then access it. For DERIVED2 users, the solution is to convert the Derived2 instance to the Base type:

Code #06

Base D2 = new Derived2 ();
D2. Printstatus ();

Output #02

public virtual void Printstatus () in Base
Inside the DERIVED2, you can access it through base:

Code #07

Base. Printstatus ();

This method is for instance members, and is accessed through the class name if the member being sealed is a static member.

4. If Base.printstatus is an implicit implementation of an interface ...

If Base implements a IFace interface:

Code #08

Interface IFace
{
void Printstatus ();
}

Class Base:iface
{
public virtual void Printstatus ()
{
Console.WriteLine ("Public virtual void Printstatus () in Base");
}
}

We just need to get Derived2 to re-implement IFace:

Code #09

Class Derived2:base, IFace
{
Public new void Printstatus ()
{
Console.WriteLine ("Public new void Printstatus () in Derived2");
}
}

The Derived1 remains unchanged. Then put:

Code #10

iface[] fs = new iface[]
{
New Base (),
New Derived1 (),
New Derived2 (),
}

Pass to:

Code #11

public void Displaystatusof (iface[] FS)
{
foreach (IFace f in FS)
{
F.printstatus ();
}
}

The output is:

Output #03

public virtual void Printstatus () in Base
public override void Printstatus () in Derived1
Public new void Printstatus () in Derived2

From the output, we can see that although the Derived2.printstatus application of new, but still participate in dynamic binding, this is because new can only cut the connection between Derived2.printstatus and Base.printstatus, and cannot sever its connection with the Iface.printstatus. I re-specify implementation IFace in the definition of DERIVED2, which will make the compiler think derived2.printstatus is an implicit implementation of iface.printstatus, so in dynamic binding derived2.printstatus was included in it.

5. Who's problem?

I have to point out that if both Base (code #01) and Derived2 (code #04) exist at the same time, one of them has a design problem. Why do you say that? The designer of Base applied virtual on printstatus to show that he wanted the derived class to be able to participate in dynamic binding by rewriting this method, that is, polymorphism, while Derived2 's designer applied new on Printstatus to show he wanted to cut Derived2. The connection between Printstatus and Base.printstatus, which would make derived2.printstatus unable to participate in the dynamic bindings expected by the designer of the Base. If it is reasonable to apply virtual (that is, the expectation of polymorphism) on the Base.printstatus, then the derived2.printstatus should be replaced by another name, if applied on the Derived2.printstatus New (that is, the veto participates in dynamic binding) is reasonable, then base.printstatus should consider whether to remove the virtual, otherwise there will be some strange behavior, such as the output #01 the third row of outputs.

If the expectation of polymorphic behavior in the inheritance system is reasonable, then the more practical approach would be to define Base as such:

Code #12

Abstract class Base
{
public abstract void Printstatus ();
}

The original implementation in Base should move down to a derived class://Code #13

Class Derived3:base
{
public override void Printstatus ()
{
Console.WriteLine ("public override void Printstatus () in DERIVED3 [originally implemented in Base]");
}
}

In this way, Derived2.printstatus will make the compilation impossible, forcing its designer to either change the name of the method or replace it with the override modifier. This compulsion makes Derived2 's designers have to reconsider the rationality of their designs.

What if the expectation of polymorphic behavior in the inheritance system is not always reasonable? For example, Stream has such a method:

Public abstract long Seek (long offset, seekorigin origin);

Now suppose I have a way to use stream.seek when working with input streams:

Code #14

public void Resume (Stream input, long offset)
{
//
Input. Seek (offset, seekorigin.begin);
//
}

When we pass an instance of NetworkStream to the resume, the resume throws a NotSupportedException because NetworkStream does not support Seek. Does this mean that there is a problem with the design of the Stream?

It is assumed that Resume is a download tool for the continuation of the breakpoint, however, not all servers support the continuation of the breakpoint, so you need to first determine whether the input stream supports the Seek operation, and then decide how to handle the input stream:

Code #15

public void Resume (Stream input, long offset)
{
if (input. CanSeek)
{
//
Input. Seek (offset, seekorigin.begin);
//
}
Else
{
//
}
}

If CanSeek is false, then you have to start over.

In fact, we do not guarantee that any of the Stream's derived classes will support a certain operation, and we cannot even guarantee that all instances from the same derived class will support a certain operation. You can imagine a prioritystream that can decide whether to provide write operations based on the permissions of the current login account, which makes it possible for someone with sufficient privileges to modify the data. Perhaps the designer of the stream has expected this to happen, so CanRead, CanSeek and CanWrite have been added to the stream.

It is important to note that the Derived2 of Code #07 may be a bad design or a useful design. In this article, it is a very bad design, if you are careful enough, you will notice that Derived2 's designers want Derived2.printstatus to bypass Base.printstatus and directly relate to Iface.printstauts, On the surface this is fine, but essentially base.printstatus and iface.printstauts are homogeneous in terms of agreement, which means that if associated with iface.printstauts, it is tantamount to admitting yourself and base.printstatus is homogeneous, so why not rewrite the printstatus directly in the DERIVED2? In the declaration problem of mixed base class and interface inheritance, I demonstrated a practical design that uses new and interface re-implementation (Interface reimplementation) to correct unexpected polymorphic behavior.

6. Finally ...

When my friend comes to me with a question, I usually do not give my answer directly, but do my best to provide him with enough information so that he can deal with the situation he is facing, after all, I will not know him better than he does, and he should form his own thoughts about his problems. I hope the prodigal son can answer his question with his own answer, because only then does that knowledge really belong to him, and I also believe that this article has provided enough information available.

C # polymorphism vs. New keyword

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.