Home Random Page


CATEGORIES:

BiologyChemistryConstructionCultureEcologyEconomyElectronicsFinanceGeographyHistoryInformaticsLawMathematicsMechanicsMedicineOtherPedagogyPhilosophyPhysicsPolicyPsychologySociologySportTourism






Nbsp;   Generic Methods

When you define a generic class, struct, or interface, any methods defined in these types can refer to a type parameter specified by the type. A type parameter can be used as a method’s parameter, a method’s return type, or as a local variable defined inside the method. However, the CLR also sup- ports the ability for a method to specify its very own type parameters. And these type parameters can also be used for parameters, return types, or local variables.


Here is a somewhat contrived example of a type that defines a type parameter and a method that

has its very own type parameter.

 

internal sealed class GenericType<T> { private T m_value;

 

public GenericType(T value) { m_value = value; }

 

public TOutput Converter<TOutput>() {

TOutput result = (TOutput) Convert.ChangeType(m_value, typeof(TOutput)); return result;

}

}

 

In this example, you can see that the GenericType class defines its own type parameter (T), and the Converter method defines its own type parameter (TOutput). This allows a GenericType to be constructed to work with any type. The Converter method can convert the object referred to by

the m_value field to various types depending on what type argument is passed to it when called. The ability to have type parameters and method parameters allows for phenomenal flexibility.

A reasonably good example of a generic method is the Swap method.

 

private static void Swap<T>(ref T o1, ref T o2) { T temp = o1;

o1 = o2; o2 = temp;

}

 

Code can now call Swap like as follows.

 

private static void CallingSwap() { Int32 n1 = 1, n2 = 2;

Console.WriteLine("n1={0}, n2={1}", n1, n2); Swap<Int32>(ref n1, ref n2); Console.WriteLine("n1={0}, n2={1}", n1, n2);

 

String s1 = "Aidan", s2 = "Grant"; Console.WriteLine("s1={0}, s2={1}", s1, s2); Swap<String>(ref s1, ref s2); Console.WriteLine("s1={0}, s2={1}", s1, s2);

}

 

Using generic types with methods that take out and ref parameters can be particularly interest- ing because the variable you pass as an out/ref argument must be the same type as the method’s parameter to avoid a potential type safety exploit. This issue related to out/ref parameters is dis- cussed toward the end of the “Passing Parameters by Reference to a Method” section in Chapter 9, “Parameters.” In fact, the Interlocked class’s Exchange and CompareExchange methods offer generic overloads for precisely this reason.1

 

 

 
 

1 The where clause will be explained in the “Verifiability and Constraints” section later in this chapter.


public static class Interlocked {

public static T Exchange<T>(ref T location1, T value) where T: class; public static T CompareExchange<T>(

ref T location1, T value, T comparand) where T: class;

}

 

Generic Methods and Type Inference

For many developers, the C# generic syntax can be confusing with all of its less-than and greater- than signs. To help improve code creation, readability, and maintainability, the C# compiler offers type inference when calling a generic method. Type inference means that the compiler attempts to determine (or infer) the type to use automatically when calling a generic method. Here is some code that demonstrates type inference.



 

private static void CallingSwapUsingInference() { Int32 n1 = 1, n2 = 2;

Swap(ref n1, ref n2);// Calls Swap<Int32>

 

String s1 = "Aidan"; Object s2 = "Grant";

Swap(ref s1, ref s2);// Error, type can't be inferred

}

 

In this code, notice that the calls to Swap do not specify type arguments in less-than/greater-than signs. In the first call to Swap, the C# compiler was able to infer that n1 and n2 are Int32s, and there- fore, it should call Swap by using an Int32 type argument.

When performing type inference, C# uses the variable’s data type, not the actual type of the object referred to by the variable. So in the second call to Swap, C# sees that s1 is a String and s2 is an Object (even though it happens to refer to a String). Because s1 and s2 are variables of dif- ferent data types, the compiler can’t accurately infer the type to use for Swap’s type argument, and it issues the following message: error CS0411: The type arguments for method 'Program. Swap<T>(ref T, ref T)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

 

A type can define multiple methods with one of its methods taking a specific data type and an- other taking a generic type parameter, as in the following example.

 

private static void Display(String s) { Console.WriteLine(s);

}

 

private static void Display<T>(T o) { Display(o.ToString()); // Calls Display(String)

}

 

Here are some ways to call the Display method.

 

Display("Jeff"); // Calls Display(String)

Display(123); // Calls Display<T>(T) Display<String>("Aidan"); // Calls Display<T>(T)


In the first call, the compiler could actually call either the Display method that takes a String or the generic Display method (replacing T with String). However, the C# compiler always prefers a more explicit match over a generic match, and therefore, it generates a call to the non- generic Display method that takes a String. For the second call, the compiler can’t call the

non-generic Display method that takes a String, so it must call the generic Display method. By the way, it is fortunate that the compiler always prefers the more explicit match; if the compiler had preferred the generic method, because the generic Display method calls Display again (but with a String returned by ToString), there would have been infinite recursion.

The third call to Display specifies a generic type argument, String. This tells the compiler not to try to infer type arguments but instead to use the type arguments that I explicitly specified. In this case, the compiler also assumes that I must really want to call the generic Display method, so the generic Display will be called. Internally, the generic Display method will call ToString on the passed-in string, which results in a string that is then passed to the non-generic Display method.

 

 


Date: 2016-03-03; view: 600


<== previous page | next page ==>
Nbsp;   Delegate and Interface Contra-variant and Covariant Generic Type Arguments | Nbsp;   Verifiability and Constraints
doclecture.net - lectures - 2014-2024 year. Copyright infringement or personal data (0.007 sec.)