Home Random Page


CATEGORIES:

BiologyChemistryConstructionCultureEcologyEconomyElectronicsFinanceGeographyHistoryInformaticsLawMathematicsMechanicsMedicineOtherPedagogyPhilosophyPhysicsPolicyPsychologySociologySportTourism






Nbsp;   Generic Interfaces

C#’s and the CLR’s support of generic interfaces offers many great features for developers. In this sec-

tion, I’d like to discuss the benefits offered when using generic interfaces.

 

First, generic interfaces offer great compile-time type safety. Some interfaces (such as the non- generic IComparable interface) define methods that have Object parameters or return types. When code calls these interface methods, a reference to an instance of any type can be passed. But this is usually not desired. The following code demonstrates.

 

private void SomeMethod1() { Int32 x = 1, y = 2; IComparable c = x;

 

// CompareTo expects an Object; passing y (an Int32) is OK c.CompareTo(y); // y is boxed here

 

// CompareTo expects an Object; passing "2" (a String) compiles

// but an ArgumentException is thrown at runtime c.CompareTo("2");

}


Obviously, it is preferable to have the interface method strongly typed, and this is why the FCL includes a generic IComparable<in T> interface.

Here is the new version of the code revised by using the generic interface.

 

private void SomeMethod2() { Int32 x = 1, y = 2; IComparable<Int32> c = x;

 

// CompareTo expects an Int32; passing y (an Int32) is OK c.CompareTo(y); // y is not boxed here

 

// CompareTo expects an Int32; passing "2" (a String) results

// in a compiler error indicating that String cannot be cast to an Int32 c.CompareTo("2"); // Error

}

 

The second benefit of generic interfaces is that much less boxing will occur when working with val- ue types. Notice in SomeMethod1 that the non-generic IComparable interface’s CompareTo method expects an Object; passing y (an Int32 value type) causes the value in y to be boxed. However, in SomeMethod2, the generic IComparable<in T> interface’s CompareTo method expects an Int32; passing y causes it to be passed by value, and no boxing is necessary.

 

NoteThe FCL defines non-generic and generic versions of the IComparable, ICollection, IList, and IDictionary interfaces, as well as some others. If you are defining a type, and

you want to implement any of these interfaces, you should typically implement the generic versions of these interfaces. The non-generic versions are in the FCL for backward compat- ibility to work with code written before the .NET Framework supported generics. The non- generic versions also provide users a way of manipulating the data in a more general, less type-safe fashion.

Some of the generic interfaces inherit the non-generic versions, so your class will have to implement both the generic and non-generic versions of the interfaces. For example, the generic IEnumerable<out T> interface inherits the non-generic IEnumerable inter- face. So if your class implements IEnumerable<out T>, your class must also implement IEnumerable.

Sometimes when integrating with other code, you may have to implement a non-generic interface because a generic version of the interface simply doesn’t exist. In this case, if any of the interface’s methods take or return Object, you will lose compile-time type safety, and you will get boxing with value types. You can alleviate this situation to some extent by using a technique I describe in the “Improving Compile-Time Type Safety with Explicit Interface Method Implementations” section near the end of this chapter.




The third benefit of generic interfaces is that a class can implement the same interface multiple

times as long as different type parameters are used.

 

The following code shows an example of how useful this could be.

 

using System;

 

// This class implements the generic IComparable<T> interface twice public sealed class Number: IComparable<Int32>, IComparable<String> {

private Int32 m_val = 5;

 

// This method implements IComparable<Int32>'s CompareTo public Int32 CompareTo(Int32 n) {

return m_val.CompareTo(n);

}

 

// This method implements IComparable<String>'s CompareTo public Int32 CompareTo(String s) {

return m_val.CompareTo(Int32.Parse(s));

}

}

 

public static class Program { public static void Main() {

Number n = new Number();

 

// Here, I compare the value in n with an Int32 (5) IComparable<Int32> cInt32 = n;

Int32 result = cInt32.CompareTo(5);

 

// Here, I compare the value in n with a String ("5") IComparable<String> cString = n;

result = cString.CompareTo("5");

}

}

 

An interface’s generic type parameters can also be marked as contra-variant and covariant, which allows even more flexibility for using generic interfaces. For more about contra-variance and covari- ance, see the “Delegate and Interface Contra-variant and Covariant Generic Type Arguments” section in Chapter 12.

 

 


Date: 2016-03-03; view: 567


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