如何将公司网站做的更好看,服务器可以做自己网站用吗,网络组建拓扑图,saas系统架构1.前言往往一些刚接触C#编程的初学者#xff0c;对于泛型的认识就是直接跳到对泛型集合的使用上#xff0c;虽然微软为我们提供了很多内置的泛型类型#xff0c;但是如果我们只是片面的了解调用方式#xff0c;这会导致我们对泛型盲目的使用。至于为什么要使用泛型#xf…1.前言往往一些刚接触C#编程的初学者对于泛型的认识就是直接跳到对泛型集合的使用上虽然微软为我们提供了很多内置的泛型类型但是如果我们只是片面的了解调用方式这会导致我们对泛型盲目的使用。至于为什么要使用泛型什么情况下定义属于自己的泛型定义泛型又能为程序带来哪些好处。要理清这些问题我们就必须深刻理解泛型的本质形成泛型编程的思维方式。接下来我将基于一个基础示例然后通过需求不断的演化示例从而让泛型在关键时刻脱颖而出以便让我们能够深刻体会泛型的作用。假设.NET没有为我们提供用于存储数据的集合而我们需要一个能够用于存储string元素的集合基于这个情况我们自定义了一个用于存储字符串的集合类class ArraryStr{public ArraryStr(){_items new string[100]; //初始化存储元素的容量只是为了演示故将容量定义为固定值}private string[] _items; //存储元素的数组private int _count; //元素总数public int Count{get { return _count; }}public void Add(string item) //新增元素{_items[_count] item;_count;}public string this[int index] //索引{get { return _items[index]; }set { _items[index] value; }}} // END ArraryStr为了验证自定义string集合的可行性我们对其进行了如下的应用1 ArraryStr arraryStr new ArraryStr();
2 arraryStr.Add(张三);
3 Console.WriteLine(arraryStr[0]);2.重复目前对于创建string类型的集合已经大功告成而此刻我们又接到了一个新的需求即我们需要一个集合存储int类型的元素。基于自定义string集合的经验来看我们可以发现string集合类型和我们即将要创建的int集合类型的结构和内容几乎是一样的。这就意味着我们可以使用江湖盛行的“复制大法”将之前的代码复制一遍然后轻微修改下即可。下面是两个集合类型代码的对比图。在早年有款热门的游戏叫做“大家来找茬”该游戏主要玩法就是在两个大致相同的图片中查找两者之间的细微差异之处。我们使用的“复制大法”促使我们编写的代码形成了可以用于这个游戏游玩的场景。“对于上面的两个代码截图你能找出图中不同的地方吗”对于软件开发者而言面对的最主要的敌人就是“变化”假设后面还会出现N个类型的元素需要我们定义集合来存储那我们是不是要将相同的代码无穷尽的复制下去DRYDont Repeat Yourself不要重复自己请记住这是作为一名软件开发者编码的原则“复制大法”很明显的违背了这个原则。3.安全和性能通过“复制粘贴”的手段可以很明显的感受到我们在做重复的事情在重复中我们可以发现集合存储的类型在增加但是集合的结构和添加元素的方法都是相同的逻辑。简单来说就是不同类型的处理其处理逻辑都是类似的。基于这个特点为了满足自定义集合能够应对所有类型的存储我们必须使用一个通用类型来作为代表此时此刻我们脑海中就能浮现出一句话object是一切类型的基类。这就意味着我们添加的所有类型都可以隐式的转换为object类型从而使得自定义集合可以添加任何类型的元素。让我们来运用这个object类型来试试class ArraryList{public ArraryList() { _items new object[100]; }private object[] _items;private int _count;public int Count{get { return _count; }}public void Add(object item){_items[_count] item;_count;}public object this[int index]{get { return _items[index]; }set { _items[index] value; }}} // END ArraryStrinternal class Program{static void Main(string[] args){ArraryList arraryList new ArraryList();arraryList.Add(张三);arraryList.Add(18);string name (string)arraryList[0];int age (int)arraryList[1];} // END Main}在上面的代码中我们结合了object是一切类型基类的特点对集合类型进行改造并成功的使用该方式的集合添加了不同类型的元素。虽然在使用的角度来看已经完美无缺(可以添加任何类型)但是获取集合元素进行赋值的时候还使用了类型强制转换的手段。这是因为这种方式存在很严重的问题主要包括以下两个方面类型安全方面如果集合的第一个元素是sting类型但是你客观认为是int类型于是你在获取时进行了int类型的强制转换这个时候代码不会提示错误且可以正常编译那么这就意味着程序在运行时会产生一个你无法预料的类型无效转换的异常。性能方面值类型元素添加到集合时必然会存在装箱操作而在获取元素并赋值给一个值类型变量时又会发生相应的拆箱操作。这种拆箱和装箱的操作在操作大量元素时会大幅度的损失程序的性能。到目前位置我们还是没有能创建一个能够存储任何类型的集合但是我们可以对于上述的示例演变的过程进行一个总结对于不同类型有相同处理逻辑的情况如果一味的复制会导致我们出现重复代码如果使用object来作为解决重复的方案会存在类型安全和性能的问题。至于如何让彻底解决这些问题这就要说到了本文讲解的主题——泛型。4.代码模板C#中有两种不同的机制来编写跨类型一个类型代替多个类型可复用的代码继承和泛型。继承的复用性来自于基类而泛型的复用性是通过带有“占位符”的代码模板类型实现的。继承实现复用是站在面向对象的角度思考的而泛型的复用是站在实现特定功能上思考的。相比于继承泛型不用遵循里氏替换原则并且能够提高类型的安全性减少类型转换带来的拆箱和装箱。怎么样理解泛型泛型本质上相当于一种“代码模板”可以用一套代码为不同类型的同一逻辑使用统一的方式实现。其中“模板”一词的概念需要进行深刻的体会。例如公司在招聘时会与用人方签订劳动合同而这个劳动合同的主要内容对于所有人来说几乎都是一样的只是在极个别的地方有所差异如薪资、姓名等。所以公司不会为某个人张三或李四去特意的制定合同而是会统一制定一份劳动合同作为模板将其中针对个人存在差异的部分通过“下划线”进行占位预留“下划线”的值将在签订合同时由具体的聘用者根据自身情况填写。对于这种模板方式的使用公司在制定合同时则不用考虑签订合同的人具体是谁因为劳动合同(模板)和使用者是分开的所以公司只用专注于合同的主要内容即可。而我们在实际的编程运用中使用泛型的目的其实和公司制定通用的劳动合同模板是一个道理。假设你的公司需要雇佣100名员工时你不希望为每一个人都制定一个专属的合同吧假设你的代码中如果遇到10个类型它们的操作处理逻辑都一样时你不希望为这个10个类型写10个处理方式吧通过上面的介绍和例子接下来我们将泛型运用到我们的示例中来代码如下1 class ArraryListT2 {3 public ArraryList() { _items new T[100]; }4 5 private T[] _items;6 private int _count;7 public int Count8 {9 get { return _count; }
10 }
11
12 public void Add(T item)
13 {
14 _items[_count] item;
15 _count;
16 }
17
18 public T this[int index]
19 {
20 get { return _items[index]; }
21 set { _items[index] value; }
22 }
23 } // END ArraryStr
24 internal class Program
25 {
26 static void Main(string[] args)
27 {
28 ArraryListstring arraryStr new ArraryListstring();
29 arraryStr.Add(张三);
30 Console.WriteLine(arraryStr[0]);
31
32 ArraryListint arraryInt new ArraryListint();
33 arraryInt.Add(18);
34 Console.WriteLine(arraryInt[0]);
35
36 } // END Main
37
38 }5.类型参数在上面的代码中我们将集合类型定义为了泛型类该类型中出现的T属于泛型中的类型参数(Type Parameter)。泛型为了达到通用处理的目的所以不能将某个具体类型作为处理的目标类型故而将要处理的类型用“T”作为一个类型占位符。“T”并不是真正的数据类型它更像是泛型使用的类型蓝图所以在使用时泛型类型的消费者必须将一个具体类型作为“类型参数”传递到尖括号内以此构造一个有明确处理类型的泛型实例。所以我们在外部使用泛型时不能以“ArraryListTlist new ArraryListT()”、“T tnew T()”这种方式去实例化泛型类型。另外“T”本身仅仅是类型参数的名称它只是代表了类型参数的标识而已这意味着我们可以使用其他字符来为类型参数命名。6.替换通过类型参数的使用我们可以得知泛型类型代码在静态阶段没有明确的类型那么在程序运行的时候它又是如何和使用时指定的“类型参数”进行对接的呢为了搞清楚这个问题下面我们来了解下泛型运行时的本质。我们编写的C#程序在编译后生成的代码并不是计算机可以直接执行的代码而是会生成CIL通用中间语言代码并包含在程序集中如果想要生成计算机可执行的代码则还需要JIT即时编译器对CIL代码进行二次编译。然而泛型类型确认其具体类型的时机就在JIT进行二次编译时JIT编译的代码如果包含了泛型的内容那么它会根据泛型类型的消费者指定的类型参数将CIL中泛型代码中的占位符T替换为一个具体的类型从而明确当前执行的泛型代码是针对哪个类型来使用的其中替换的过程是由CLR在运行时进行主导JIT来实际操作完成的。这个在运行时确认了类型的泛型又被称之为“封闭类型”反之在运行时确认之前的泛型称为“开放类型”。泛型使用占位符在运行时替换具体类型的机制其实和本文中例举劳动合同模板使用“下划线”的方式有同样的思想。在指定劳动合同模板时对于聘用者的姓名并不能写一个具体的名字因为模板的目的是为了通用化所以对于名字采用了“下划线”的方式。当公司与某个具体的人签订合同的时候劳动合同模板中的下划线将由聘用者根据自身情况填写。回到泛型中其使用思想也是如此我们使用泛型的目的是为了让多个类型的处理通用化所以在定义泛型代码的时候并不能指定一个具体类型故使用类型参数T进行代替这个类型参数T就相当于劳动合同模板中的“下划线”当泛型在实际运行的时候JIT会根据泛型消费者指定的具体类型与占位符T进行替换。7.总结本文并不是专门适用于介绍泛型的使用细节的文章而是通过一个实例根据需求不断演化的过程对泛型一步步深入从而更加深刻的理解泛型的使用初衷相比了解泛型“只言片语”而言形成泛型的编程概念和思维显得尤为重要。在泛型的机制中我们可以将不同类型存在相同处理逻辑的情况形成一个通用的方案从而不在为特定的类型进行编码用一套通用的代码模板会服务于更多的类型并且在使用上能保证类型安全和提供良好的性能。原文地址https://www.cnblogs.com/green-jcx/p/16671687.html