Home Random Page


CATEGORIES:

BiologyChemistryConstructionCultureEcologyEconomyElectronicsFinanceGeographyHistoryInformaticsLawMathematicsMechanicsMedicineOtherPedagogyPhilosophyPhysicsPolicyPsychologySociologySportTourism






Nbsp;   Be Careful with Explicit Interface Method Implementations

It is critically important for you to understand some ramifications that exist when using EIMIs. And because of these ramifications, you should try to avoid EIMIs as much as possible. Fortunately, generic interfaces help you avoid EIMIs quite a bit. But there may still be times when you will need to use them (such as implementing two interface methods with the same name and signature). Here are the big problems with EIMIs:

■ There is no documentation explaining how a type specifically implements an EIMI method,

and there is no Microsoft Visual Studio IntelliSense support.

 

■ Value type instances are boxed when cast to an interface.

 

■ An EIMI cannot be called by a derived type.

 

Let’s take a closer look at these problems.

 

When examining the methods for a type in the .NET Framework reference documentation, explicit interface method implementations are listed, but no type-specific help exists; you can just read the general help about the interface methods. For example, the documentation for the Int32 type shows that it implements all of IConvertible interface’s methods. This is good because developers know that these methods exist; however, this has been very confusing to developers because you can’t call an IConvertible method on an Int32 directly. For example, the following method won’t compile.

 

public static void Main() { Int32 x = 5;

Single s = x.ToSingle(null); // Trying to call an IConvertible method

}

 

When compiling this method, the C# compiler produces the following message: messagepil17: 'int' does not contain a definition for 'ToSingle'. This error message confuses the developer because it’s clearly stating that the Int32 type doesn’t define a ToSingle method when, in fact, it does.

To call ToSingle on an Int32, you must first cast the Int32 to an IConvertible, as shown in the following method.

 

public static void Main() { Int32 x = 5;

Single s = ((IConvertible) x).ToSingle(null);

}

 

Requiring this cast isn’t obvious at all, and many developers won’t figure this out on their own. But an even more troublesome problem exists: casting the Int32 value type to an IConvertible also boxes the value type, wasting memory and hurting performance. This is the second of the big prob- lems I mentioned at the beginning of this section.


The third and perhaps the biggest problem with EIMIs is that they cannot be called by a derived class. Here is an example.

 

internal class Base : IComparable {

 

// Explicit Interface Method Implementation Int32 IComparable.CompareTo(Object o) {

Console.WriteLine("Base's CompareTo"); return 0;

}

}

 

internal sealed class Derived : Base, IComparable {

 

// A public method that is also the interface implementation public Int32 CompareTo(Object o) {

Console.WriteLine("Derived's CompareTo");

 

// This attempt to call the base class's EIMI causes a compiler error:



// error CS0117: 'Base' does not contain a definition for 'CompareTo' base.CompareTo(o);

return 0;

}

}

 

In Derived’s CompareTo method, I try to call base.CompareTo, but this causes the C# compiler to issue an error. The problem is that the Base class doesn’t offer a public or protected CompareTo method that can be called; it offers a CompareTo method that can be called only by using a variable that is of the IComparable type. I could modify Derived’s CompareTo method so that it looks like the following.

 

// A public method that is also the interface implementation public Int32 CompareTo(Object o) {

Console.WriteLine("Derived's CompareTo");

 

// This attempt to call the base class's EIMI causes infinite recursion IComparable c = this;

c.CompareTo(o);

 

return 0;

}

 

In this version, I am casting this to an IComparable variable, c. And then, I use c to call CompareTo. However, the Derived’s public CompareTo method serves as the implementation for Derived’s IComparableCompareTo method, and therefore, infinite recursion occurs. This could be fixed by declaring the Derived class without the IComparable interface, like the following.

 

internal sealed class Derived : Base /*, IComparable */ { ... }


Now the previous CompareTo method will call the CompareTo method in Base. But sometimes you cannot simply remove the interface from the type because you want the derived type to imple- ment an interface method. The best way to fix this is for the base class to provide a virtual method in addition to the interface method that it has chosen to implement explicitly. Then the Derived class can override the virtual method. Here is the correct way to define the Base and Derived classes.

 

internal class Base : IComparable {

 

// Explicit Interface Method Implementation Int32 IComparable.CompareTo(Object o) {

Console.WriteLine("Base's IComparable CompareTo");

return CompareTo(o); // This now calls the virtual method

}

 

// Virtual method for derived classes (this method could have any name) public virtual Int32 CompareTo(Object o) {

Console.WriteLine("Base's virtual CompareTo"); return 0;

}

}

 

internal sealed class Derived : Base, IComparable {

 

// A public method that is also the interface implementation public override Int32 CompareTo(Object o) {

Console.WriteLine("Derived's CompareTo");

 

// Now, we can call Base's virtual method return base.CompareTo(o);

}

}

 

Note that I have defined the virtual method above as a public method, but in some cases, you will prefer to make the method protected instead. It is fine to make this method protected instead of public, but that will necessitate other minor changes. This discussion clearly shows you that EIMIs

should be used with great care. When many developers first learn about EIMIs, they think that they’re cool and they start using them whenever possible. Don’t do this! EIMIs are useful in some circum- stances, but you should avoid them whenever possible because they make using a type much more difficult.

 

 


Date: 2016-03-03; view: 576


<== previous page | next page ==>
Nbsp;   Improving Compile-Time Type Safety with Explicit Interface Method Implementations | Nbsp;   Design: Base Class or Interface?
doclecture.net - lectures - 2014-2024 year. Copyright infringement or personal data (0.007 sec.)