Introduction:
In C #2.0, Generics do not support variability (variability refers to Covariance and inversion). We know that there is variability in Object-oriented Inheritance, when the return type of the method declaration is stream, we can return a filestream type in the implementation. In this case, an implicit conversion exists -- fromFilestream type (subclass reference) --> stream type (parent class reference ),And the array of the reference type also has thisSubclass reference --> parent class referenceFor example, string [] can be converted to object [] (that is, such code can be compiled by: String [] STRs = new string [3]; object [] objs = STRs;). At this time, we will definitely wonder if generic parameters in the generic type can also support such conversions? However, it is not supported in C #2.0, but because of this demand, Microsoft also considers this problem, therefore, the generic covariant and inverter are introduced in C #4.0. The following describes the specific content of the covariant and inverter in C #4.0.
I. Covariance
Covariance refers to -- generic type parameters can beThe derived class is implicitly converted to the base class (we can remember this way, and the covariance is a harmonious change. In our life, we generally say that our children are like their parents, this may sound more harmonious, so it is easy to remember the change), Introduced in C #4.0OutKeyword to mark generic parameters. In order to better describe the generic covariance, the following uses the. NET class libraryPublic interface ienumerable <out T>This interface is used to demonstrate an example to help you understand generic covariant:
List <Object> listobject = new list <Object> (); List <string> liststrs = new list <string> (); // The parameter type received by the addrange method is ienumerable <t> collection // the following code passes in a list <string> type parameter. // In msdn, we can see that this interface is defined as -- ienumerable <int T>. // Therefore, ienumerable <t> wildcard type parameter t supports covariant, therefore, you can // convert list <string> to ienumerable <string> (this is supported by the inherited covariance) // because the ienumerable <in T> API delegate supports covariance, you can convert ienumerable <string> to the --> ienumerable <Object> type. // The type cannot be converted during compiler verification. Listobject. addrange (liststrs); // liststrs. addrange (listobject); // Error
Liststrs. addrange (listobject); a compile-time error occurs (cannot be converted from list <Object> to ienumerable <string>, because list <Object> can be converted to ienumerable <Object> due to the inherited covariance, ienumerable <out T> does not support inversion, that is, conversion from object to string, in this case, an error occurs in the figure below .), The error message is as follows:
Ii. Inverter
Inversion refers to the generic type parameter that can be retrieved fromThe base class is implicitly converted to a derived class (you can use examples in your life to help you remember the opposite thing-if your parents are long like their children, they will definitely feel awkward, this problem is often found in high school Chinese), Introduced in C #4.0InKeyword to mark the wildcard parameter support for the inverter. to better illustrate the generic inverter, the following uses the interface in the. NET class libraryPublic interface icomparer <in T>To demonstrate an example to help you understand generic inverters.:
Class program {static void main (string [] ARGs) {list <Object> listobject = new list <Object> (); list <string> liststrs = new list <string> (); // The parameter type received by the addrange method is ienumerable <t> collection // the following code passes in a list <string> type parameter. // In msdn, we can see that this interface is defined as -- ienumerable <int T>. // Therefore, ienumerable <t> wildcard type parameter t supports covariant, therefore, you can // convert list <string> to ienumerable <string> (this is supported by the inherited covariance) // because the ienumerable <in T> API delegate supports covariance, you can convert ienumerable <string> to the --> ienumerable <Object> type. // The type cannot be converted during compiler verification. Listobject. addrange (liststrs); // success /// liststrs. addrange (listobject); // error icomparer <Object> objcomparer = new testcomparer (); icomparer <string> objcomparer2 = new testcomparer (); // The sort method of the liststrs variable of the List <string> type receives icomparer <string> type parameters. // However, the following code passes in parameters of the icomparer <Object> type, to compile successfully, you must be able to convert it to the icomparer <string> type. // It is precisely because the icomparer <in T> generic interface supports inverter, therefore, object conversion to string type is supported. // the following line of code can be compiled. net 4. Versions earlier than 0 will certainly be compiled incorrectly. // you can change the project's target framework. net Framework 3.5 or a lower-level version // so that the following line of code will encounter a compilation error, because the wildcard covariant and inverter are newly added features in C #4.0, and. net 4.0 corresponds to C #4.0. Liststrs. sort (objcomparer); // correct // error // listobject. sort (objcomparer2) ;}} public class testcomparer: icomparer <Object> {public int compare (Object obj1, object obj2) {return obj1.tostring (). compareto (obj2.tostring ());}}
In the above Code, if you use listobject. when sort (objcomparer2) is used, a compilation error occurs. The cause of the error can be understood as the cause of the error in the above covariant. The following is an error:
To further illustrate that the generic covariant and inverter are in C #4.0 (C #4.0 is. net Framework 4.0) versions do not support generic covariant and inverter. You can also find this in msdn. The following is a comparison (you can view it on msdn. When the version is changed to 3.5 or a lower-level version, check whether the generic definition has no out or in keywords, that is, the previous version does not support generic variability ):
Iii. Considerations for covariant and Inverter
Not all types support generic covariant and inverter. The following lists some notable and clear points in the generic covariant and your inverter:
1. only the interfaces and delegates support covariant and invert parameters (such as func <out tresult> and action <in T>). The type parameters of class or generic methods do not support covariant and invert.
2. covariant and invert are only applicable to reference types. value types do not support covariant and invert (because there is a reference conversion for variability, and value type variables store the object itself, so list <int> cannot be converted to ienumerable <Object>.
3. type parameters must be marked with in or out.
4. the variability of delegation should not be used in multicast delegation. I believe this is something that many people have not noticed. The following is an example to illustrate why you may know when you encounter such a problem:
// The following initialization delegate uses the lambda expression. The Lambda expression will be described in the following topics.
Func <string> stringfunc = () => ""; func <Object> objectfunc = () => new object (); func <Object> combined = stringfunc + objectfunc;
The code above can be compiled. Because generic func <out T> supports covariant, convert func <string> to func <Object> type, however, the object itself is still of the func <string> type, but delegate. the combine method requires that the parameter be of the same type -- otherwise, the method cannot determine the type of delegate to be created (is func <string> type or func <Object> ?), Therefore, the above Code will throw argumetexception when running (the error message is -- the delegate must have the same type ). We can slightly modify the above Code to prevent running errors.
Func <string> stringfunc = () => ""; // convert the delegate type func <Object> tempfunc = new func <Object> (stringfunc ); func <Object> objectfunc = () => new object (); func <Object> combined = tempfunc + objectfunc;
Iv. Summary
Although this series may not help much in actual development, I personally think that the Foundation still needs to be disturbed. Only after the foundation is completed can we fly farther, it is easier to master new technologies, so I will keep writing this series, hoping to help you consolidate basic knowledge. (I think students in school should pay more attention to the consolidation of basic knowledge, and then write some examples to deepen their understanding of basic knowledge ).
This topic has been introduced here (another interesting topic for generics is the interaction between the covariant and the inverter. For details, refer to this article: http://www.cnblogs.com/Ninputer/archive/2008/11/22/generic_covariant.html (because I also know this from this article, if you are interested, you can go to the above link to see how )), next topic I will introduce another new feature in C #2.0 --Null type.