物流网站毕业设计,汉口网站建设,软件商店最新版下载,网站开发维护承担的法律责任目录 一、概述
二、C#中的泛型
继续栈的示例
三、泛型类
#xff08;一#xff09;声明泛型类
#xff08;二#xff09;创建构造类型
#xff08;三#xff09;创建变量和实例
#xff08;四#xff09;比较泛型和非泛型栈
四、类型参数的约束
#xff08;一…目录 一、概述
二、C#中的泛型
继续栈的示例
三、泛型类
一声明泛型类
二创建构造类型
三创建变量和实例
四比较泛型和非泛型栈
四、类型参数的约束
一Where子句
二约束类型和次序
五、泛型方法
一声明泛型方法
二调用泛型方法
三泛型方法的示例
六、泛型结构
七、泛型委托
八、泛型接口
一使用泛型接口的示例
二泛型接口的实现必须唯一 一、概述
泛型是用于处理算法、数据结构的一种编程方法。泛型的目标是采用广泛适用和可交互性的形式来表示算法和数据结构以使它们能够直接用于软件构造。泛型类、结构、接口、委托和方法可以根据它们存储和操作的数据的类型来进行参数化。泛型能在编译时提供强大的类型检查减少数据类型之间的显示转换、装箱操作和运行时的类型检查。泛型类和泛型方法同时具备可重用性、类型安全和效率高等特性这是非泛型类和非泛型方法无法具备的。泛型通常用在集合和在集合上运行的方法中。
泛型主要是提高了代码的重要性。例如可以将泛型看成是一个可以回收的包装箱A。如果在包装箱A上贴上苹果标签就可以在包装箱A里装上苹果进行发送如果包装箱A上贴上地瓜标签就可以在包装箱A里装上地瓜进行发送。 二、C#中的泛型
泛型generic特性提供了一种更优雅的方式可以让多个类型共享一组代码。泛型允许我们声明类型参数化的代码用不同的类型进行实例化。也就是说我们可以用“类型占位符”来写代码然后在创建类的实例时指明真实的类型。
我们应该清楚类型不是对象而是对象的模板。同样泛型类型也不是类型而是类型的模板。 C#提供了5种泛型类、结构、接口、委托和方法。注意前面4个是类型而方法是成员。 继续栈的示例
在栈的示例中MyIntStack和MyFloatStack两个类的声明主体差不多只不过处理由栈保存的值类型的位置不同。
在 MyIntStack中这些位置由int类型占据。在MyFloatStack中这些位置被float占据。
通过如下步骤我们可以从MyIntStack创建一个泛型类。
1在MyIntStack类定义中使用类型占位符T而不是float来替换int。
2修改类名称为MyStact。
3在类名后放置T。
结果就是如下的泛型类声明。由尖括号和T构成的字符串表明T是类型的占位符不一定是字符T它可以是任何标识符。在类声明的主体中每一个T都会被编译器替换为实际类型。 三、泛型类
创建和使用常规的、非泛型的类有两个步骤声明类和创建类的实例。但是泛型类不是实际的类而是类的模板所以我们必须先从它们构建实际的类类型然后创建这个类类型的引用和实例。
1在某些类型上使用占位符来声明一个类。
2为占位符提供真实类型。这样就有了真实类的定义填补了所有的“空缺”。该类型称为构造类型
3创建构造类型的实例。 一声明泛型类
声明一个简单的泛型类和声明普通类差不多区别如下
在类名之后放置一组尖括号在尖括号中用逗号分隔的占位符字符串来表示需要提供的类型。这叫作类型参数type parameter。在泛型类声明的主体中来使用类型参数来表示替代类型。
例如如下代码声明了一个叫作SomeClass的泛型类。类型参数列在尖括号中然后当作真实类型在声明的主体中使用。
class SomeClass T1,T2// T1T2为类型参数
{public T1 SomeVar;public T2 OtherVar;
}
在泛型类的声明中并没有特殊的关键字。取而代之的是尖括号中的类型参数列表它可以区分泛型类与普通类的声明。 二创建构造类型
一但声明了泛型类型我们就需要告诉编译器能使用哪些真实类型来替代占位符类型参数。编译器获取这些真实类型并创建构造类型用来创建真实对象的模板。
创建构造类型的语法如下包括列出类名以及在尖括号中提供真实类型来替代类型参数。替代类型参数的真实类型叫作类型实参type argument。
SomeClassshort, int //尖括号内为类型实参
编译器接受了类型实参并且替换泛型类主体中的相应类型参数产生了构造类型——从它创建真实类型的实例。
类型参数和类型实参的区别
泛型类声明上的类型参数用作类型的占位符在创建构造类型时提供的真实类型是类型实参。 三创建变量和实例
在创建引用和实例方面构造类类型的使用和常规类型差不多。例如如下代码演示了两个类对象的创建。
MyNonGenClass MyNGC new MyNonGenClass ();SomeClassshort, int mySc1 new SomeClassshort, int();//SomeClassshort, int为构造类
var mySc2 new SomeClassshort, int();
第一行显示了普通非泛型类型对象的创建。第二行代码显示了SomeClass泛型类型对象的创建使用short和int类型进行实例化。这种形式和上面一行差不多只不过把普通类型名改为构造类形式。第三行和第二行的语法一样没有在等号两边都列出构造类型而是使用var关键字让编译器使用类型引用。 四比较泛型和非泛型栈
非泛型栈和泛型栈之间的区别
非泛型泛型源代码大小更大需要为每一种类型编写一个新的实现更小不管构造类型的数量有多少只需要一个实现可执行文件大小无论每一个版本的栈是否会被使用都会在编译的版本中出现可执行文件中只会出现有构造类型的类型写的难易度易于书写因为它更具体比较难写因为它更抽象维护的难易度更容易出问题因为所有修改需要应用到每一个可用的类型上易于维护因为只需要修改一个地方 四、类型参数的约束
在泛型栈的示例中栈除了保存和弹出它包含的一些项之外没有做任何事情。它不会尝试添加、比较项也不会做其他任何需要用到项本身的运算符的事情。这是有原因的。由于泛型栈不知道它们保存的项的类型是什么所以也就不会知道这些类型实现的成员。
然而所有的C#对象最终都从object类继承。因此栈可以确认的是这些保存的项都实现了object类的成员包括ToString、Equals以及GetType方法。
只要我们的代码不访问它处理的一些类型的对象或者只要它始终是object类型的成员泛型类就可以处理任何类型。符合约束的类型参数叫作未绑定的类型参数。然而如果代码尝试使用其他成员编译器会产生一个错误信息。 一Where子句
约束使用where子句列出
每一个有约束的类型参数都有自己的where子句如果形参有多个约束它们在where子句中使用逗号分隔。
where子句的语法如下
where Typeparam : constraint, contraint, ...
有关where子句的要点如下
它们在类型参数列表的关闭尖括号之后列出。它们不使用逗号或其他符号分隔。它们可以以任何次序列出。where是上下文关键字所以可以在其他上下文中使用。
例如如下泛型类有3个类型参数。T1是未绑定的类型参数。对于T2只有Customer类型的类或从Customer派生的类才能用作类型实参。而对于T3只有实现IComparable接口的类才能用作类型实参。
class MyClass T1, T2, T3where T2 : Customer //T2的约束 where T3 : IComparable //T3的约束
{...
} 二约束类型和次序
约束类型描述类名只有这个类型的类或从它派生的类才能用作类型实参class任何引用类型包括类、数组、委托和接口都可以用作类型实参struct任何值类型都可以用作类型实参接口名只有这个接口或实现这个接口的类型才能用作类型实参new()任何带有无参公共构造函数的类型都可以用作类型实参。这叫做构造函数约束
where子句可以以任和次序列出。然而where子句中的约束必须有特定的顺序。
最多只能有一个主约束而且必须放在第一位可以有任意多的接口名称约束如果存在构造函数约束则必须放在最后。 五、泛型方法
除了定义泛型类之外还可以定义泛型方法。在泛型方法中泛型类型用方法声明来定义。泛型方法可以在非泛型类中定义。
与其他泛型不一样方法是成员不是类型。泛型方法可以在泛型和非泛型类以及结构和接口中声明。
一声明泛型方法
泛型方法具有类型参数列表和可选的约束
1泛型方法有两个参数列表
封闭在圆括号内的方法参数列表封闭在尖括号内的类型参数列表
2要声明泛型方法需要
在方法名称之后和方法参数列表之前放置类型参数列表在方法参数列表后放置可选的约束子句 二调用泛型方法
要调用泛型方法应该在方法调用时提供类型实参如下所示 下面演示了一个叫作DoStuff的泛型方法的声明它接受两个类型参数。其后是两次方法调用每使用不同的类型参数。编译器使用每个构造实例产生方法的不同版本。 推断类型
如果我们为方法传入参数编译器有时可以从方法参数的类型中推断出应用作泛型方法的类型参数的类型。这样就可以使方法调用更简单可读性更强。
例如下面的代码声明了MyMethod它接受了一个与类型参数同类型的方法参数。 如果我们使用int类型的变量调用MyMethod方法调用中的类型参数的信息就多余了因为编译器可以从方法参数中得知它是int。 由于编译器可以从方法参数中推断类型参数我们可以省略类型参数和调用中的尖括号。 三泛型方法的示例
如下的代码在一个叫作Simple的非泛型类中声明了一个叫作ReverseAndPrint的泛型方法。这个方法把任意类型的数组作为其参数。Main声明了3个不同的数组类型然后使用每一个数组调用方法两次。
第一次使用特定数组调用了方法并显式使用类型参数。而第二次让编译器推断类型。
class Simple //非泛型类
{static public void ReverseAndPrint T(T[] arr) //泛型方法{ Array.Reverse(arr);foreach(T item in arr) //使用类型实参TConsole.Write(${item.Tostring()},);Console.WrtiteLine();}
}class Program
{static void Main(){//创建各种类型的数组 var intArray new int[] {3, 5, 7, 9, 11};var stringArray new string[] {first, second, third};var doubleArray new double[] {3.567, 7.891, 2.345};Simple.ReverseAndPrintint(intArray); //调用方法Simple.ReverseAndPrint(intArray); //推断类型并调用Simple.ReverseAndPrintstring(stringArray);//调用方法Simple.ReverseAndPrint(stringArray); //推断类型并调用Simple.ReverseAndPrintdouble(doubleArray);//调用方法Simple.ReverseAndPrint(doubleArray); //推断类型并调用}
} 六、泛型结构
与泛型类相似泛型结构可以有类型参数和约束。泛型结构的规则和条件与泛型类是一样的。
例如下面的代码声明了一个叫作PieceOfData的泛型结构它保存和获取一块数据其中的类型在结构类型时定义。Main创建了两个构造类型的对象——一个使用int而另一个使用string。
struct PieceOfDataT //泛型结构
{public PieceOfData (T value) {_data value;}private T _data;public T Data{get {return _data;}set {_data value;}}
}class Program
{static void Main(){var intData new pieceOfDataint(10);var stringData new PieceOfDatastring(Hi there.);Console.WriteLine($intData {intData.Data});Console.WriteLine($stringData {stringData.Data});}
}
这段代码产生了如下的输出 intData 10 StringData Hi there 七、泛型委托
泛型委托和非泛型委托非常相似不过类型参数决定了能接受什么样的方法。
1要声明泛型委托在委托名称之后、委托参数列表之前的尖括号中放置类型参数列表。 2注意有两个参数列表委托形参列表和类型参数列表。
3类型参数的范围包括
返回类型形参列表约束子句
如果代码给出了一个泛型委托的示例。在Main中泛型委托MyDelegate使用string类型的实参实例化并且使用PrintString方法初始化。
delegate void MyDelegateT(T value); //泛型委托class Simple
{static public void PrintString(string s) //方法匹配委托{Console.WriteLine(s);}static public void PrintUpperString(string s) //方法匹配委托{Console.WriteLine(${s.ToUpper()});}}class Program
{static void Main(){var myDel new MyDelegatestring(Simple.PrintString);//创建委托的实例myDel Simple.PrintUpperString; //添加方法myDel(Hi There.);}
}
这段代码产生了如下的输出 Hi There. HI THERE. 八、泛型接口
泛型接口允许我们编写形参和接口成员返回类型是泛型类型参数的接口。泛型接口的声明和非泛型接口的声明差不多但是需要在接口名称之后的尖括号中放置类型参数。
例如如下代码声明了叫作IMyIfc的泛型接口。
泛型类Simple实现了泛型接口Main实例化了泛型类的两个对象一个是int类型另外一个是string类型。
一使用泛型接口的示例
如下示例演示了泛型接口的另外两项能力
与其他泛型相似用不同类型参数实例化的泛型接口的实例是不同的接口我们可以在非泛型类型中实现泛型接口。
例如下面的代码与前面的示例相似但在这里Simple是实现泛型接口的非泛型类。其实它实现了两个IMyIfc实例。一个实例使用int类型实例化而另一个使用string类型实例化。 二泛型接口的实现必须唯一
实现泛型类型接口时必须保证类型实参的组合不会在类型中产生两个重复的接口。
例如在下面的代码中Simple类使用了两个ImyIfc接口的实例化。
第一个是构造类型使用类型int进行实力化。第二个有一个类型参数但不是实参。
对于泛型接口使用两个相同接口本身并没有错问题在于这么做会产生一个潜在的冲突因为如果把int作为类型实参来替代第二个接口中的S的话Simple可能会有两个相同类型的接口二这是不允许的。
interface IMyIfcT
{T ReturnIt(T inValue);
}class SimpleS : IMyIfcint, IMyIfcS //错误
{public int ReturnIt(int inValue) //实现第一个接口{return inValue;}public S ReturnIt(S inValue) //实现第二个接口{ //入过它不是int类型的return inValue; //将和第一个接口一样}
}
说明泛型接口的名字不会和非泛型冲突。例如在前面代码中我们还可以声明一个名为ImyIfc的非泛型接口。