The cause of this post is a friend's question: http://community.csdn.net/Expert/TopicView3.asp? Id = 5118454
In the reply to this post, I failed to give a convincing answer. Under his questioning, I was forced to rethink his question. I felt that I had misunderstood the question, the answer is similar, so it is necessary to explain it again here.
This friend has the following questions:
Interface iinterfacea
{
Void dosomething ();
}
Interface iinterfaceb: iinterfacea
{
New void dosomething (); // hide the member of the base Interface
}
// Are the two interfaces different? It seems that iinterfaceb does not have any function to hide the member dosomething of iinterfacea.
// Can you give me a simple example (CODE) to help me understand it. Thank you.
He asked about the significance of such an application. In other words, is it necessary to do so? Where can this application be used?
If there is no practical application, it is really difficult to imagine that there is such a demand scenario, so I found such an example in the vs random document. It was originally used to demonstrate the difference between implicit interface implementation and explicit interface implementation.
Bytes -----------------------------------------------------------------------------------------
Explicit interface implementation also allows the programmer to implement two interfaces with the same member name, and provides an implementation for each interface member. In this example, the size of the box is displayed in both the metric and imperial units. The box class implements the ienglishdimensions and imetricdimensions interfaces, which indicate different measurement systems. The two interfaces have the same member name length and width.
Example
// Declare the English units interface:
Interface ienglishdimensions
{
Float length ();
Float width ();
}
// Declare the metric units interface:
Interface imetricdimensions
{
Float length ();
Float width ();
}
// Declare the box class that implements the two interfaces:
// Ienglishdimensions and imetricdimensions:
Class box: ienglishdimensions, imetricdimensions
{
Float lengthinches;
Float widthinches;
Public box (float length, float width)
{
Lengthinches = length;
Widthinches = width;
}
// Explicitly implement the members of ienglishdimensions:
Float ienglishdimensions. Length ()
{
Return lengthinches;
}
Float ienglishdimensions. Width ()
{
Return widthinches;
}
// Explicitly implement the members of imetricdimensions:
Float imetricdimensions. Length ()
{
Return lengthinches * 2.54f;
}
Float imetricdimensions. Width ()
{
Return widthinches * 2.54f;
}
Static void main ()
{
// Declare a class instance box1:
Box box1 = new box (30366f, 20366f );
// Declare an instance of the English units interface:
Ienglishdimensions edimensions = (ienglishdimensions) box1;
// Declare an instance of the metric units interface:
Imetricdimensions mdimensions = (imetricdimensions) box1;
// Print dimensions in English units:
System. Console. writeline ("length (in): {0}", edimensions. Length ());
System. Console. writeline ("width (in): {0}", edimensions. Width ());
// Print dimensions in metric units:
System. Console. writeline ("length (CM): {0}", mdimensions. Length ());
System. Console. writeline ("width (CM): {0}", mdimensions. Width ());
}
}
Output
Length (in): 30
Width (in): 20
Length (CM): 76.2
Width (CM): 50.8
Reliable Programming
If you want to use the English Unit for the default measurement, implement the length and width methods normally, and explicitly implement the length and width methods from the imetricdimensions interface:
// Normal implementation:
Public float length ()
{
Return lengthinches;
}
Public float width ()
{
Return widthinches;
}
// Explicit implementation:
Float imetricdimensions. Length ()
{
Return lengthinches * 2.54f;
}
Float imetricdimensions. Width ()
{
Return widthinches * 2.54f;
}
In this case, you can access the imperial unit from the class instance, and access the metric unit from the interface instance:
Public static void test ()
{
Box box1 = new box (30366f, 20366f );
Imetricdimensions mdimensions = (imetricdimensions) box1;
System. Console. writeline ("length (in): {0}", box1.length ());
System. Console. writeline ("width (in): {0}", box1.width ());
System. Console. writeline ("length (CM): {0}", mdimensions. Length ());
System. Console. writeline ("width (CM): {0}", mdimensions. Width ());
}
Bytes -----------------------------------------------------------------------------------------
I have modified the interface definition:
Interface ienglishdimensions
{
Float length ();
Float width ();
}
Interface imetricdimensions: ienglishdimensions
{
New float length ();
New float width ();
}
In the case of a friend's question, whether the subinterface uses new to overwrite (note that I use "Overwrite" instead of "hide ".) The basic interface members get the same effect. However, in the MS example after I modified the interface definition, the New Keyword shows its meaning. If I modify the interface definition like this:
Interface ienglishdimensions
{
Float length ();
Float width ();
}
Interface imetricdimensions: ienglishdimensions
{
// New float length ();
// New float width ();
}
This example cannot be compiled. It will prompt you
"Imetricdimensions. length" in the explicit interface declaration is not an interface member.
"Imetricdimensions. width" in the explicit interface declaration is not an interface member.
The compilation method is to display and implement ienglishdimensions in the class box, while implicitly implement imetricdimensions. However, we will find that the printed result is as follows:
Output
Length (in): 30
Width (in): 20
Length (CM): 30
Width (CM): 20
Now, the benefits of inheriting interfaces and providing new keywords to overwrite basic interface members are obvious.
I have ensured that the interface definition of imetricdimensions is strictly consistent with that of imetricdimensions. My box supports two metering systems at the same time. They are strictly the same in terms of Member definitions, but they are in different hexadecimal formats.
I can also write it as in the original MS example and define it completely as two unrelated interfaces, but if I want to add any member for ienglishdimensions, I have to modify the definition of imetricdimensions at the same time. If I forget it, or what kind of condensation occurs here, my box cannot support new members when applying the imetricdimensions metric system.
The above is the [personal view of yuanmu Fisherman].
If you are interested, you can also read this article.
I would like to thank Eldest Brother 11z for his inspiration and reference in my thoughts on this issue.
I am also grateful to my sh_city (high) friend for asking me questions. I have paid attention to and thought deeply about this issue.
Bytes ----------------------------------------------------------------------------------------
In addition, when discussing this issue with the 11z eldest brother, the 11z boss thought that C # was originally designed to facilitate version management and control. I didn't quite understand it yesterday. Today I found evidence in the msdn article. The original text will be referenced below.
The original article is about class inheritance, but the same is true for conversion to interfaces.
Bytes ---------------------------------------------------------------------------------------
The C # language is specially designed so that version control between the base classes and derived classes in different libraries can continue to develop and maintain backward compatibility. This has many meanings. For example, this means that the introduction of a new member with the same name as a member in the dispatch class in the base class is fully supported in C # and will not cause unexpected behavior. It also means that the class must explicitly declare whether a method needs to override an inherited method or a new method that only hides an inherited method with a similar name.
C # Allow the derived class to contain methods with the same name as the base class method.
The base class method must be defined as virtual.
If the method in the derived class does not have the new or override keyword before it, the compiler will issue a warning that the method will execute the operation like there is a new keyword.
If the method in the derived class has a new keyword before it, the method is defined as a method independent from the method in the base class.
If the method in the derived class has the override keyword before it, the object of the derived class will call this method without calling the base class method.
You can use the base keyword in the derived class to call the base class method.
The override, virtual, and new keywords can also be used in attributes, indexers, and events.
By default, the C # method is not a virtual method. If a method is declared as a virtual method, any class that inherits the method can implement its own version. To make a method a virtual method, you must use the virtual modifier in the method declaration of the base class. Then, the derived class can use the override keyword to override the basic virtual method, or use the new keyword to hide the virtual method in the basic class. If the override keyword and New Keyword are not specified, the compiler will issue a warning and the methods in the derived class will hide the methods in the base class. For more information, see the compiler warning cs0108.
To demonstrate the above situation in practice, we assume that Company A has created a class named graphicsclass, which is used by your program. Graphicsclass is similar to the following:
C # copy code
Class graphicsclass
{
Public Virtual void drawline (){}
Public Virtual void drawpoint (){}
}
Your company uses this class and you use it to derive your own class when adding a new method:
C # copy code
Class yourderivedgraphicsclass: graphicsclass
{
Public void drawrectangle (){}
}
You have not encountered any problems when using the application until Company A releases a new version of graphicsclass, which is similar to the following:
C # copy code
Class graphicsclass
{
Public Virtual void drawline (){}
Public Virtual void drawpoint (){}
Public Virtual void drawrectangle (){}
}
Now, the new version of graphicsclass contains a method called drawrectangle. At first, everything went fine. The new version is still Binary compatible with the old version-All Software deployed will continue to work even if a new class is installed in the computer system. In your derived class, any existing call to the method drawrectangle will continue to reference your version.
However, once you re-compile the application using a new version of graphicsclass, you will receive a warning from the compiler. For more information, see the compiler warning cs0108.
This warning reminds you to consider how your drawrectangle method works in your application.
If you want to use your method to override the new base class method, use the override keyword, as shown below:
C # copy code
Class yourderivedgraphicsclass: graphicsclass
{
Public override void drawrectangle (){}
}
The override keyword ensures that any object derived from yourderivedgraphicsclass uses the derived class version of drawrectangle. Objects derived from yourderivedgraphicsclass can still use the base keyword to access the base class version of drawrectangle, as shown below:
C # copy code
Base. drawrectangle ();
If you do not want to use your method to override the new base class method, pay attention to the following items. To avoid confusion between the two methods, you can rename your method. The rename method may be time-consuming and error-prone, and is not practical in some cases. However, if your project is relatively small, you can use the reconstruction option of Visual Studio to rename the method. For more information, see refactoring classes and types.
Alternatively, you can use the new keyword in the derived class definition to prevent this warning, as shown below:
C # copy code
Class yourderivedgraphicsclass: graphicsclass
{
Public new void drawrectangle (){}
}
Use the New Keyword to tell the compiler that your definition will hide the definition contained in the base class. This is the default action.
Rewrite and Method Selection
When a method is specified in a class, if multiple methods are compatible with the call (for example, there are two methods with the same name, and their parameters are compatible with the passed parameters ), then the C # compiler selects the best method for calling. The following methods will be compatible:
C # copy code
Public class derived: Base
{
Public override void dowork (int param ){}
Public void dowork (double PARAM ){}
}
When dowork is called in an instance of derived, the C # compiler will first try to make the call compatible with the dowork version originally declared on derived. The override method is not declared on the class, but a new implementation of the method declared on the base class. Only when the C # compiler cannot match a method call with the original method on derived can it try to match the call with an override method with the same name and compatible parameters. For example:
C # copy code
Int val = 5;
Derived d = new derived ();
D. dowork (VAL); // calldowork (double ).
Since the variable Val can be implicitly converted to the double type, the C # compiler calls dowork (double) instead of dowork (INT ). There are two ways to avoid this situation. First, avoid declaring the new method with the same name as the virtual method. Second, you can forcibly convert the derived instance to base to search for the base class method list by the C # compiler, so that it calls the virtual method. Because it is a virtual method, the implementation of dowork (INT) on derived will be called. For example:
C # copy code
(Base) d). dowork (VAL); // calldowork (INT) on derived.
Qltouming)
2006-11-02