12.Generics
benifit:
1.make developers extremely productive is code reuse, which is the ability to derive a class that inherits all of the capabilities of a base class.
The derived class can simply override virtual methods or add some new methods to customize the behavior of the base class to meet the developer’s needs.
2.is another mechanism offered by the common language runtime (CLR) and programming languages that provides one more form of code reuse: algorithm reuse.
such as sorting, searching, swapping, comparing, or converting
Most algorithms are encapsulated in a type, and the CLR allows the creation of generic reference types as well as generic value types.but it does not allow the creation of generic enumerated types.
3.Source code protection
The developer using a generic algorithm doesn’t need to have access to the algorithm’s source code.
With C++ templates, however, the algorithm’s source code must be available to the developer who is using the algorithm.
4.Type safety
When a generic algorithm is used with a specific type, the compiler and the CLR understand this and ensure that only objects compatible with the specified data type are used with the algorithm.
Attempting to use an object of an incompatible type will result in either a compiler error or a run-time exception being thrown.
In the example, attempting to pass a String object to the Add method results in the compiler issuing an error.
5.Cleaner code
Because the compiler enforces type safety, fewer casts are required in your source code, meaning that your code is easier to write and maintain.
In the last line of SomeMethod, a developer doesn’t need to use a (DateTime) cast to put the result of the indexer (querying element at index 0) into the dt variable.
6.Better performance
Before generics, the way to define a generalized algorithm was to define all of its members to work with the Object data type. If you wanted to use the algorithm with value type instances, the CLR had to box the value type instance prior to calling the members of the algorithm. boxing causes memory allocations on the managed heap, which causes more frequent garbage collections, which, in turn, hurt an application’s performance.
Because a generic algorithm can now be created to work with a specific value type, the instances of the value
type can be passed by value, and the CLR no longer has to do any boxing.
In addition, because casts are not necessary (see the previous bullet), the CLR doesn’t have to check the type safety of the attempted cast, and this results in faster code too.
using the generic List algorithm with the Int32 type is much faster than using the non-generic ArrayList algorithm with Int32.because using a value type (Int32) with ArrayList causes a lot of boxing operations to occur
using reference types is not as momentous.the times and number of garbage collections are about the same. So it doesn’t appear that the generic List algorithm is of any benefit here.
However, keep in mind that when using a generic algorithm, you also get cleaner code and compile-time type safety
So although the performance improvement is not huge, the other benefits you get when using a generic algorithm are usually an improvement.
其他知识:
1.Microsoft’s design guidelines state that generic parameter variables should either be called T or at least start with an uppercase T (as in TKey and TValue).
The uppercase T stands for type, just as an uppercase I stands for interface (as in IComparable).
2.the CLR generates native code for each method the first time the method is called for a particular data type. This will increase an application’s working set size, which will hurt performance
1.Generics in the Framework Class Library
1.the most obvious use.the FCL defines several generic collection classes available for your use(System.Collections.Generic namespace,System.Collections.ObjectModel namespace,System.Collections.Concurrentnamespace)
2.Microsoft recommends that programmers use the generic collection classes and now discourages use of the non-generic collection classes
(1)get the type safety, cleaner code, and better performance
(2)have a better object model.For example, fewer methods are virtual, resulting in better performance,and new members have been added to the generic collections to provide new functionality.
3.The collection classes implement many interfaces, and the objects that you place into the collections can implement interfaces that the collection classes use for operations such as sorting and searching.
The FCL ships with many generic interface definitions so that the benefits of generics can be realized when working with interfaces as well.
The commonly used interfaces are contained in the System.Collections.Generic namespace.
4.The new generic interfaces are not a replacement for the old non-generic interfaces;
in many scenarios,you will have to use both.The reason is backward compatibility.
For example, if the List<T> class implemented only the IList<T> interface, no code could consider a List<DateTime> object an IList.
5.the System.Array class, the base class of all array types, offers many static generic methods, such as AsReadOnly, BinarySearch, ConvertAll, Exists, Find, FindAll……
2.Generics Infrastructure
Generics were added to version 2.0 of the CLR, and it was a major task that required many people working for quite some time.
to make generics work, Microsoft had to do the following:
1.Create new Intermediate Language (IL) instructions that are aware of type arguments
2.Modify the format of existing metadata tables so that type names and methods with generic parameters could be expressed.
3.Modify the various programming languages (C#, Microsoft Visual Basic .NET, etc.) to support the new syntax, allowing developers to define and reference generic types and methods
4.Modify the compilers to emit the new IL instructions and the modified metadata format
5.Modify the just-in-time (JIT) compiler to process the new type-argument–aware IL instructions that produce the correct native code.
6.Create new reflection members so that developers can query types and members to determine if they have generic parameters. Also, new reflection emit members had to be defined so that developers could create generic type and method definitions at run time.
7.Modify the debugger to show and manipulate generic types, members, fields, and local variables.
8.Modify the Microsoft Visual Studio IntelliSense feature to show specific member prototypes when using a generic type or a method with a specific data type.
Open and Closed Types
how the CLR creates an internal data structure for each and every type in use by an application?
1. the CLR will create an internal type object for each of these.This applies to reference types (classes), value types (structs), interface types, and delegate types
These data structures are called type objects. Well, a type with generic type parameters is still considered a type
2.However, a type with generic type parameters is called an open type, and the CLR does not allow any instance of an open type to be constructed
3.the CLR allocates a type’s static fields inside the type object. So each closed type has its own static fields
In other words, if List<T> defined any static fields, these fields are not shared between a List<DateTime> and a List<String>;
4.if a generic type defines a static constructor, this constructor will execute once per closed type.
Sometimes people define a static constructor on a generic type to ensure that the type arguments will meet certain criteria.
5.The CLR has a feature called constraints that offers a better way for you to define a generic type indicating what type arguments are valid for it.
Unfortunately,constraints do not support the ability to limit a type argument to enumerated types only,which is why the previous example requires a static constructor to ensure that the type is an enumerated type.
how the CLR prevents an instance of an interface type from being constructed?
a type with generic type parameters is called an open type
1.When code references a generic type, it can specify a set of generic type arguments.
If actual data types are passed in for all of the type arguments, the type is called a closed type, and the CLR does allow instances of a closed type to be constructed.
2.However, it is possible for code referencing a generic type to leave some generic type arguments unspecified.
This creates a new open type object in the CLR, and instances of this type cannot be created.
the exception’s string message indicates that the type still contains some generic parameters.
the type names end with a backtick (`) followed by a number. The number indicates the type’s arity
Generic Types and Inheritance
1.A generic type is a type, and as such, it can be derived from any other type.
2.When you use a generic type and specify type arguments, you are defining a new type object in the CLR, and the new type object is derived from whatever type the generic type was derived from
In other words, because List<T> is derived from Object, List<String> and List<Guid> are also derived from Object.
Similarly, because DictionaryStringKey<TValue> is derived from Dictionary<String, TValue>, DictionaryStringKey<Guid> is also derived from Dictionary<String, Guid>.
3.specifying type arguments doesn’t have anything to do with inheritance hierarchies
示例:
1.the m_next field must refer to another node that has the same kind of data type in its m_data field.
This means that the linked list must contain nodes in which all data items are of the same type (or derived type).
2.if I use Node<Object> everywhere, but then I would lose compile-time type safety, and value types would get boxed.
3.So a better way to go would be to define a non-generic Node base class and then define a generic TypedNode class (using the Node class as a base class).
Now, can have a linked list in which each node can be of a specific data type (not Object), get compile-time type safety, and avoid the boxing of value types.
write code to create a linked list in which each node is a different data type
Generic Type Identity
1.Sometimes generic syntax confuses developers.
After all, there can be a lot of less-than (<) and greater-than (>) signs sprinkled throughout your source code, and this hurts readability
2.To improve syntax, some developers define a new non-generic class type that is derived from a generic type and that specifies all of the type arguments.
示例:
方式一:
方式二:有问题
(1)the code that creates a list can be rewritten more simply (without less-than and greater-than signs),making your source code easier to read
(2)but lose type identity and equivalence
sameType will be initialized to false
(2.1)because you are comparing two different type objects. This also means that a method prototyped as accepting a DateTimeList will not be able to have a List<DateTime> passed to it.
(2.2)However, a method prototyped as accepting a List<DateTime> can have a DateTimeList passed to it because DateTimeList is derived from List<DateTime>.
Programmers may become easily confused by all of this.
方式三:正确
C# does offer a way to use simplified syntax to refer to a generic closed type while not affecting type equivalence at all;
can use the good-old using directive at the top of your source code file
(1)the using directive is really just defining a symbol called DateTimeList.
As the code compiles, the compiler substitutes all occurrences of DateTimeList with System.Collections.Generic.List<System.DateTime>.
This just allows developers to use a simplified syntax without affecting the actual meaning of the code, and therefore, type identity and equivalence are maintained.
方式四:正确
use C#’s implicitly typed local variable feature, where the compiler infers the type of a method’s local variable from the type of the expression you are assigning to it
Code Explosion
how?
1.When a method that uses generic type parameters is JIT-compiled
the CLR takes the method’s IL,substitutes the specified type arguments, and then creates native code that is specific to that method operating on the specified data types.
This is exactly what you want and is one of the main features of generics.
2.However, there is a downside to this: the CLR keeps generating native code for every method/type combination.
This is referred to as code explosion. This can end up increasing the application’s working set substantially, thereby hurting performance
the CLR has some optimizations built into it to reduce code explosion
1.if a method is called for a particular type argument, and later, the method is called again using the same type argument, the CLR will compile the code for this method/type combination just once.
So if one assembly uses List<DateTime>, and a completely different assembly (loaded in the same AppDomain) also uses List<DateTime>, the CLR will compile the methods for List<DateTime> just once. This reduces code explosion substantially.
2.the CLR considers all reference type arguments to be identical, and so again, the code can be shared.
because all reference type arguments or variables are really just pointers (all 32 bits on a 32-bit Windows system and 64 bits on a 64-bit Windows system) to objects on the heap, and object pointers are all manipulated in the same way.
For example, the code compiled by the CLR for List<String>’s methods can be used for List<Stream>’s methods, because String and Stream are both reference types. In fact, for any reference type, the same code will be used
3.But if any type argument is a value type, the CLR must produce native code specifically for that value type.
The reason is because value types can vary in size.
And even if two value types are the same size (such as Int32 and UInt32, which are both 32 bits), the CLR still can’t share the code because different native CPU instructions can be used to manipulate these values.
3.Generic Interfaces
the ability to define generic reference and value types was the main feature of generics. However, it was critical for the CLR to also allow generic interfaces
benifit:
Without generic interfaces, any time you tried to manipulate a value type by using a non-generic interface (such as IComparable),boxing and a loss of compile-time type safety would happen again. This would severely limit the usefulness of generic types.
And so the CLR does support generic interfaces.
how?
1.A reference or value type can implement a generic interface by specifying type arguments
2.A reference or value type can implement a generic interface by leaving the type arguments unspecified
4.Generic Delegates
The CLR supports generic delegates
benifit:
1.to ensure that any type of object can be passed to a callback method in a type-safe way.
2.allow a value type instance to be passed to a callback method without any boxing
delegate :
1. is really just a class definition with four methods: a constructor, an Invoke method, a BeginInvoke method,and an EndInvoke method.
2.When you define a delegate type that specifies type parameters, the compiler defines the delegate class’s methods, and the type parameters are applied to any methods having parameters/return types of the specified type parameter.
compiling:
5.Delegate and Interface Contra-variant and Covariant Generic Type Arguments
Delegate
Each of a delegate’s generic type parameters can be marked as covariant or contra-variant.
benifit:
allows you to cast a variable of a generic delegate type to the same delegate type where the generic parameter types differ
A generic type parameter can be any one of the following:
1.Invariant
Meaning that the generic type parameter cannot be changed
2.Contra-variant
Meaning that the generic type parameter can change from a class to a class derived from it.
In C#, you indicate contra-variant generic type parameters with the in keyword.
Contra-variant generic type parameters can appear only in input positions such as a method’s argument.
3.Covariant
Meaning that the generic type argument can change from a class to one of its base classes.
In C#, you indicate covariant generic type parameters with the out keyword.
Covariant generic type parameters can appear only in output positions such as a method’s return
type.
how to use it?
1.
the generic type parameter T is marked with the in keyword, making it contra-variant; and the generic type parameter TResult is marked with the out keyword, making it covariant.
2.When using delegates that take generic arguments and return types.
it is recommended to always specify the in and out keywords for contra-variance and covariance whenever possible
because doing this has no ill effects and enables your delegate to be used in more scenarios.
示例:
if I have a variable declared as follows.
I can cast it to another Func type, where the generic type parameters are different.
Because you can pass a String to a method that wants an Object (because String is derived from Object), and because you can take the result of a method that returns an ArgumentException and treat it as an Exception (because Exception is a base class of ArgumentException), the code above compiles and is known at compile time to preserve type safety.
相关知识点:
1.Variance applies only if the compiler can verify that a reference conversion exists between types.
In other words, variance is not possible for value types because boxing would be required.
In my opinion, this restriction is what makes these variance features not that useful.
example:
can’t call it passing in a reference to a List<DateTime> object because a reference conversion doesn’t exist between the DateTime value type and Object even though DateTime is derived from Object.
solve this problem by declaring ProcessCollection as follows:add
2.the big benefit of ProcessCollection(IEnumerable<Object> collection) is that there is only one version of the JITted code.
However, with ProcessCollection<T>(IEnumerable<T>collection), there is also only one version of the JITted code shared by all Ts that are reference types.
You do get other versions of JITted code for Ts that are value types, but now you can at least call the method passing it a collection of value types.
3.variance is not allowed on a generic type parameter if an argument of that type is passed to a method by using the out or ref keyword
example:
causes the compiler to generate the following error message: Invalid variance: The type parameter 'T' must be invariantly valid on 'SomeDelegate<T>.Invoke(ref T)'. 'T' is contravariant.
4.why they must explicitly put in or out on generic type parameters?
interface
an interface with a covariant generic type parameter
Because T is covariant, it is possible to have the following code compile and run successfully
6.Generic Methods
7.Generics and Other Members
8.Verifiability and Constraints
12.Generics的更多相关文章
- python 各模块
01 关于本书 02 代码约定 03 关于例子 04 如何联系我们 1 核心模块 11 介绍 111 内建函数和异常 112 操作系统接口模块 113 类型支持模块 114 正则表达式 115 语言支 ...
- Python Standard Library
Python Standard Library "We'd like to pretend that 'Fredrik' is a role, but even hundreds of vo ...
- 在mybatis中写sql语句的一些体会
本文会使用一个案例,就mybatis的一些基础语法进行讲解.案例中使用到的数据库表和对象如下: article表:这个表存放的是文章的基础信息 -- ------------------------- ...
- JDK1.5新特性(六)……Generics
概述 Generics - This long-awaited enhancement to the type system allows a type or method to operate on ...
- Swift进阶 - 12个技巧
听说你已经学习Swift几个月了,有没有想更进一步成为Swift高手的想法?我这里有11招秘技,各位施主且听我慢慢道来,结个善缘. 1. 扩展(Extension) 任务: 求数字的平方. // 菜鸟 ...
- AndroidStudio — Error:Failed to resolve: junit:junit:4.12错误解决
原博客:http://blog.csdn.net/u013443865/article/details/50243193 最近使用AndroidStudio出现以下问题: 解决:打开app下的buil ...
- 读过MBA的CEO更自私?《哈佛商业评论》2016年第12期。4星
老牌管理杂志.每期都值得精度.本期我还是给4星. 以下是本书中的一些内容的摘抄: 1:他们发现在Airbnb上,如果客人姓名听起来像黑人,那么比名字像白人的客人的接受率会低16%.#45 2:对立组织 ...
- 12个小技巧,让你高效使用Eclipse
集成开发环境(IDE)让应用开发更加容易.它们强调语法,让你知道是否你存在编译错误,在众多的其他事情中允许你单步调试代码.像所有的IDE一 样,Eclipse也有快捷键和小工具,这些会让您感觉轻松许多 ...
- 第12章 Linux系统管理
1. 进程管理 1.1 进程查看 (1)进程简介 进程是正在执行的一个程序或命令(如ls命令也是一个进程),每个进程都是一个运行的实体,都有自己的地址空间,并占用一定的系统资源. (2)进程管理的作用 ...
随机推荐
- 【python cookbook】【字符串与文本】12.文本过滤和清理
问题:例如清除在web页面表单中填入了pýtĥöñis这样的文本 解决方法:str.translate()方法 s = 'p\xfdt\u0125\xf6\xf1\x0cis\tawesome\r\n ...
- 161108、Java IO流读写文件的几个注意点
平时写IO相关代码机会挺少的,但却都知道使用BufferedXXXX来读写效率高,没想到里面还有这么多陷阱,这两天突然被其中一个陷阱折腾一下:读一个文件,然后写到另外一个文件,前后两个文件居然不一样? ...
- Delphi中CoInitialize之探究
CoInitialize(LPVOID),它将以特定参数调用CoInitializeEx,为当前单元初始化COM库,并标记协同模式为单线程模式.参数必须为NULL.这是关于OLE和COM的问题. Co ...
- Linux/Unix中的#!和!#
是不是在Terminal输入命令的时候,输入了很长的一个路径,然后发现还有在同一条命令中再输一次的时候很恼火,其实Shell是提供了trick的,就是使用!#(和#!不同哦) 习惯写脚本的猿,通常对于 ...
- Mac OS finder : 显示和隐藏文件[夹] show and hide files or folders
Finder默认是不显示隐藏文件[夹]的,要显示出怎么办? 要显示的话,可以GUI(graphic user interface)和CLI(command line interface)两种方式 CL ...
- vlc分析
vlc的主界面对应的代码在vlc-2.2.1\modules\gui\qt4\main_interface.cpp.在相同目录下的qt4.cpp的module模块open函数里边new出实例: /* ...
- JavaEE基础(十)
1.面向对象(package关键字的概述及作用) A:为什么要有包 将字节码(.class)进行分类存放 包其实就是文件夹 B:包的概述 举例: 学生:增加,删除,修改,查询 老师:增加,删除,修改, ...
- 常用的math函数
<?php //1.abs — 绝对值 echo abs(-77); //ceil — 进一法取整 ...
- java 堆栈 静态
所以静态变量和非静态变量的区别就在于静态变量可以用来计数,而非静态变量则不行. 理解了内存,就理解了一切,就理解了各种各样的语言.所有的语言无非都是这样:局部变量分配内存永远在栈里面,new出来的东西 ...
- SQLServer学习笔记<>.基础知识,一些基本命令,单表查询(null top用法,with ties附加属性,over开窗函数),排名函数
Sqlserver基础知识 (1)创建数据库 创建数据库有两种方式,手动创建和编写sql脚本创建,在这里我采用脚本的方式创建一个名称为TSQLFundamentals2008的数据库.脚本如下: ...