专注:本文版权所有,不得自由转载

前言

泛型不仅能够由此来举办容器,仍可以提供代码复用的一手。在泛型的涉企下,许多企划虽可能更小巧,更富有扩充性。明天本人哪怕来演示一个动泛型增强的抽象工厂形式。我们精通,抽象工厂(Abstract
Factory)形式是以工厂和产品全部抽象化,一个虚无工厂生成一组抽象产品,而一个有血有肉工厂则转变具体产品之一个一定组合。它可以保持这种相关对象成的一致性,并令用户不欲了解工厂和制品的现实性实现。传统的Abstract
Factory首要缺点是系列因强,可复用性弱。一个虚无工厂便是也一个特定需要而计划,通常不克让外急需抽象工厂的场地使用。而且固然抽象工厂可以用实际生产任务委派给一定类型的厂子,但这种委派是索要经祥和纯代码实现的,没可以用言语所提供的悬空特性。我们前几日底任务便是编制一个无对准一定产品系列和多少的泛型抽象工厂,当你待一定的虚幻工厂时,可天天复用无需再定义专门的抽象工厂实现。

前面几乎日同学告诉自己他老师告诉他,泛型是概念一种植通用的点子,至于怎么用泛型他的答案依旧定义一栽通用的法门,当时本人为从不学,还非明了啊,毕竟人家是电脑专业的科班生,我本没有发言权,只是怀疑的记录了这些荒唐的定论打算将来看看是休是本着之,这有限上竟将泛型学了刹那间,其实她定义的非只是是措施,自己感觉到他即便是同样种植标准代码执行功用的沙盘,这样最好不爱错,并把咱平常由此的箱拆箱操作过程给省了,提升了编译器的实施效用,。至于为何用泛型这一个自己一般已经注脚白了,泛型多用来集合类操作,我于此地随意的拿出C#概念之ArrayList的 Add方法的定义大家一齐探访:

咱俩率先由只生成一个出品之厂子方法先导,以当下作为泛工厂的原材料。很明朗,可以计划这样一个接口作为工厂方法的沙盘:

publicvirtual int Add (

public interface IFactory<T>
{
    T Create();
}

Object value

是厂生产一个T类型的目的。当您兑现之工厂时,应该让T为架空产品的型——即产品通用的基类。比如我们得以实现一个动无参数构造函数来创设对象的OpNewFactory实现:

)

public class OpNewFactory<TAbstractProduct, TProduct> : IFactory<TAbstractProduct>
    where TProduct : TAbstractProduct, new()
{
    public TAbstractProduct Create()
    {
        return new TProduct();
    }
}

能够看我们得以往ArrayList里添加任何项目标要素,假若暴发一个string类型的str字符串它当增长到ArrayList lib的历程被其实开展了装箱操作,即object value=str;那么我们于收获之值得时候要那样用string s=(string) lib[0];不可知脱(string)否则会唤起而,

后来例子可以看来,你该只是实现抽象类型的IFactory接口,并转具体品种。现在大家做得了了纯粹产品的厂方法模板,就要起来定义生产多独产品的架空工厂接口了。.NET泛型帮忙按类参数个数举行重载,就是说,我们可以定义生产一个、八只、三独……等又数目标纸上谈兵工厂接口,而用和一个名字。(汗吧,这虽是所谓扶助“任意数目”的伎俩)这里不不了假使拷贝代码,不过别担心,纯拷贝而已,使用的时刻只是相当爽快的哦。大家坐产二种植产品类其它抽象工厂也例介绍。能免可知定义成这样吗?

不当 1 无法以项目“object”隐式转换为“string”。存在一个显式转换(是否少强制转换?)

public interface IAbstractFactory<T1, T2>
{
    T1 Create();
    T2 Create(); //编译错误!!!
}

只是若若这样描绘:int a =(int) lib[0];程序在运转前是无力回天报错的,只要一旦运行就会合出现非凡,而那些不当还足以以泛型轻松搞定,让您于编译时就得发现错误,具体的便扣留而怎么了然了,我以篇章里从未写任何概念的语法格式,因为这几个既没有必要说,这是常识,出来混这个自然是若知道的,呵呵。玩笑啊……欢迎新手同学来自己的博客沟通学习,我为旨在你们可吗我敞开怀抱,因为我既是无是电脑专业的学员,甚至达到了大学我都不再是理工类的学习者。我无心扎上了文科专业去叱咤风云啦,哎,这一个文科专业名字太来接触科学技术的意味了。我喜欢 ……..

嗯不!方法无克因回到路区分重载,只好依赖参数类型重载。可是此我们肯定不可能为此T1和T2作为参数,因为这多少个点子就是为着养T1和T2准备的,怎么可以接受它当做参数为?难道只要命名为Create1和Create2吗?这可怜为难接受,我们期望生措施可以反映产品之色,怎么可以叫1同2呢。为了缓解者问题,大家引入了TypeToken<T>类型,它的定义如下:

 

public sealed class TypeToken<T>
{
    static private TypeToken<T> instanceValue = new TypeToken<T>();
    static public TypeToken<T> Instance
    {
        get { return instanceValue; }
    }

 关于泛型的两只重大概念:

    private TypeToken() { }
}

 

这仿佛没有成员,并且每个项目实参只可以创制一个实例,因而代价可是小。但就是是顿时小小的的实例上带有其色实参的类型信息,由此得以看做判断函数重载的基于。我们因此TypeToken<T>作为有别于生产函数重载的因,实现如下:

泛型类型形式参数(类型形参):是泛型类型或者泛型方法等概念着的挤占位符。类型形参一般以丰富写字母 T 开始,如若光暴发一个项目形参,

public interface IAbstractFactory<T1, T2>
{
    T1 Create(TypeToken<T1> token);
    T2 Create(TypeToken<T2> token);
}

一般用 T 来表示。

前几日我们对抽象工厂实现具体工厂。具体工厂便是下生产各各类产品之十足工厂来成实现。由此而如出各级种档次的纯工厂便可以直接组合生成肤浅工厂,而无论是需定义一个好像来开就宗事。注意,对每种数目标纸上谈兵工厂接口都需针对应生成一个有血有肉工厂的兑现,这里我特对生成两独产品的言传身教:

 构造泛型类型(构造类型):是吗泛型类型定义的泛型类型参数指定项目拿到的结果。

public class ConcreteFactory<T1, T2> : IAbstractFactory<T1, T2>
{
    private IFactory<T1> factory1;
    private IFactory<T2> factory2;

 泛型类型实际参数(类型实参):是替换泛型形参的别样类型。

    public ConcreteFactory(IFactory<T1> f1, IFactory<T2> f2)
    {
        factory1 = f1;
        factory2 = f2;
    }

格:是加于泛型类型参数上的限定。使用泛型类型的客户端不克替换不饱这个约束之门类参数。

    public T1 Create(TypeToken<T1> token)
    {
        return factory1.Create();
    }

 

    public T2 Create(TypeToken<T2> token)
    {
        return factory2.Create();
    }
}

泛型类:

public static class ConcretFactory
{
    public static ConcreteFactory<T1, T2> NewFactory<T1, T2>(IFactory<T1> f1, IFactory<T2> f2)
    {
        return new ConcreteFactory<T1, T2>(f1, f2);
    }
}

泛型类型可以按照项目形参的数码举行“重载”,也固然是鲜单门类表明可以使用同样之标识符,只要这半只讲明具有不同数量的类参数

留意,我而声称了一个尚无项目参数的ConcretFactory类,用一个静态方法来变化泛型ConcretFactory的实例,那是盖用泛型方法可揣测类型参数,使得大家得以不必输入尖括号或Of语句,而泛型类则没有这效率。现在大功告成!我们因此一个例子来演示这多少个泛型抽象工厂的办事情景。现在若我们需要一个生育PC的肤浅工厂,需要生产两栽浮泛产品:处理器以及内存。处理器和内存的抽象和现实贯彻如下:

 即可。例如:

澳门总统娱乐 1澳门总统娱乐 2Processor
和 Ram
public abstract class Processor
{
    public abstract string Model { get; }
}

 class A { };

public abstract class Ram
{
    public abstract int Frequency { get;}
}

class A<T> { };

public class PentiumProcessor : Processor
{
    public override string Model
    {
        get { return “Pentium Extreme Edition 955”; }
    }
}

class A<U, V> { };

public class AthlonProcessor : Processor
{
    public override string Model
    {
        get { return “Athlon 64 X2 FX-60”; }
    }
}

 

public class DDRRam : Ram
{
    public override int Frequency
    {
        get { return 400; }
    }
}

此时只要我们以概念一个 class A<C>; 或 class A<A, B> { }; 就会合报错,为啥吧,原因大粗略,这即是自身面前提到的这么些好写字母本

public class DDR2Ram : Ram
{
    public override int Frequency
    {
        get { return 533; }
    }
}

 身没有多生意义,只是一个(等待替换的茫然实际参数的)占位符即类型参数。非泛型类类表明的吃指定的基类或者基接口可以是构造类型但必须是查封构造类型。(也不怕.NET 的 CLR 的 JIT 将泛型 IL 和处女数据易为本机代码,并以拖欠过程上将类型形参替换为品种实参)不过非克是

下边的代码演示了哪些随心所欲生成为想如若的空洞工厂接口及连忙从现有单一产品工厂组合成特定的具体工厂实现。

 类型形参,而于基类或者基接口的效率域中可涵盖类型形参。下边我进行生详细解释,例如:

class Program
{
    static IAbstractFactory<Processor, Ram> ComputerFactory(string type)
    {
        if (type == “Intel”)
        {
            return ConcretFactory.NewFactory(
                new OpNewFactory<Processor, PentiumProcessor>(), 
                new OpNewFactory<Ram, DDR2Ram>());
        }
        else if (type == “AMD”)
        {
            return ConcretFactory.NewFactory(
                new OpNewFactory<Processor, AthlonProcessor>(),
                new OpNewFactory<Ram, DDRRam>());
        }

 

        //unknown type
        return null;
    }

usingSystem; 

    static void Main(string[] args)
    {
        //Yield a computer of Intel
        IAbstractFactory<Processor, Ram> factory1 = ComputerFactory(“Intel”);

 

        Ram ram1 = factory1.Create(TypeToken<Ram>.Instance);
        Processor cup1 = factory1.Create(TypeToken<Processor>.Instance);

namespaceGeneric

        Console.WriteLine(“An Intel Computer”);
        Console.WriteLine(“CPU Model: {0}”, cup1.Model);
        Console.WriteLine(“Memory Frequency: {0} MHz”, ram1.Frequency);

{

        Console.WriteLine();

class A<U, V>

        //Yield a computer of AMD
        IAbstractFactory<Processor, Ram> factory2 = ComputerFactory(“AMD”);

{

        Ram ram2 = factory2.Create(TypeToken<Ram>.Instance);
        Processor cup2 = factory2.Create(TypeToken<Processor>.Instance);

public virtual void F1(U a, V b)

        Console.WriteLine(“An AMD Computer”);
        Console.WriteLine(“CPU Model: {0}”, cup2.Model);
        Console.WriteLine(“Memory Frequency: {0} MHz”, ram2.Frequency);
    }
}

{

总括:大家就此泛型技术成功地增进了原来重用性较逊色之泛工厂,演示了泛型在加强抽象性和代码用方面顶尖之价值。

Console.WriteLine(“F1遭受寓的参数的 CTS 类型为:\n{0}\n{1}”,

a.GetType(), b.GetType());

}

}

interface I<T>

{

 

T F2(T x);

//基类或者基接口的功用域中得以涵盖类型形参

 

}

class ChildTest1:A<string, string>

{

//重写基类的 F1术

public override void F1(string a, string b)

{

Console.WriteLine(a+b);

}

}

class ChidTest2:A<string ,int>,I<string>

{

//实现基接口中的方法

public string F2(string x)

{

return (“F2带有的参数值为:”+x);

}

//该类隐藏了基类的 F1艺术

public new void F1(string a, int b)

{

Console.WriteLine(“ChidTest2类隐藏了基类的 F1办法”);

}

}

//测试类

class Test

{

static void Main(string[] args)

{

//泛型类 A 只出起头化类型参数后才来意义

A<string, int> a = new A<string, int>();//注意:其中 A<string,

int>为构造类型,也就是是初叶化类型形参

ChildTest1 cd1 = new ChildTest1();

ChidTest2 cd2 = new ChidTest2();

a.F1(“123”,123);

cd1.F1(“ChildTest1类更写了基类的”,”F1措施”);

cd2.F1(“123”,123);

Console.WriteLine(cd2.F2(“123”));

Console.ReadKey(true);

}

}

}

 

当点的代码中自己只是介绍了非泛型类的存续,那么泛型类的存续是无是平吧?这一个我们可预先自己想同一惦记,我以道到泛型接口的时刻

 会提到,下边继续游说一下啊泛型类的成员的特色。泛型类吃存有的分子还好直接当构造类型或者构造类型的一律有来用兼容类enclosed class)中的品种形参。当公共语言运行时使用一定的封构造类型时,所现身的每个项目形参都为轮换该构造类型提供的种实参。例如:

 

usingSystem;

  

namespaceGeneric

{

class A<T>

{

//定义两独品类字段

public T a; //作为构造类型的相同局部(成员)使用类型形参 T

public A<T> b = null;//直接当构造类型使用类型形参 T

//实例构造函数,其中 this 是 A<T>的实例

public A(T x)

 

{

this.a = x;

this.b = this;

}

}

//测试类

class Test

{

static void Main(string[] args)

{

A<string> A1 = new A<string>(“Hello World”);

Console.WriteLine(A1.a);

Console.WriteLine(A1.b.a);

A<int> A2 = new A<int>(123);

Console.WriteLine(A1.a);

Console.WriteLine(A1.b.a);

Console.ReadKey(true);

}

}

}

 

恐这边有同学不晓得我说的封构造类型,我前提到了构造类型,我于此处当解释一下,例如A<T>和A<string>都是构造类型,我们将(使用一个要多单项目形参的构造类型)A<T>称为开放构造类型;将(不实用类型形参(即以实参)的构造类型)A<string>称为封闭构造类型。此外对于地点的代码我可如此表明:即构造类型成员好直接或者局部作为开构造类型使用类形参,能够一向或一些看成

封闭构造类型使用项目实参。

泛型接口

 我从前提到了类型形参只是一个(等待替换的茫然实际参数的)占位符。那么要这样接口interface I<T>,interface I<A> , interface I<C>其实是同等的,同时跟泛型类一样,可以依据项目形参的数举办“重载”,也不怕是个别独品类阐明可以选取同一之标识符,只要这简单单讲明

具备不同数额的品类参数。那么我们这么想,倘诺我要为此一个接近实现interfaceI<string>和
I <string> 和

 

interface I <int>

 

interface I<T>

{

void F();

}

,我们是不是可以使形如:

class A<U, V> : I<U>, I<V> //之后交替为interface I <string> 和interface I <int>

{

void I<U>.F()

{

}

void I<V>.F()

{

}

}

 

那般编译器便会唤醒:

错误 1

 

“Generic.A<U,V>”不克以落实“Generic.I<U>”和“Generic.I<V>”,原因是她对于某些类型形参替换可以展开联合

也就是说,当以泛型类实现泛型接口必须试有可能的泛型接口的构造类型(例如I<U>)保持唯一,否则编译器不能确定拖欠为某泛型接口的突显成员调用这多少个情势。 可能当I<U>就是I<V>)。可是大家可以以不同继承级别指定的接口举行统一。例如:

interface I<T>

{

void F();

}

class Base<U> : I<U>

{

void I<U>.F()

{

Console.WriteLine(“I<U>.F()”);

}

}

class Derived<U, V> : Base<U>, I<V>

{

void I<V>.F()

{

Console.WriteLine(“I<U>.F()”);

}

}

class Test

{

public static void Main()

{

I<int> test1 =new Base<int>();

I<int> test2= new Derived<string, int>();

test1.F();

test2.F();

Console.ReadKey();

Console.ReadKey();

}

}

自打下边的代码可以见见,即便Derived<U,V> 同时实现了I<U>和I<V> , test2.F() 这 里 将 调 用 I<V>() 的 方 法 , 实 际 上 实 在Derived<U,V>中还实现了I<int>.那里我们重临地点我说泛型类的时光,泛型类继承的风味,这里一看代码便已经明白了,泛型类继承的基类或者基接口可以是放的构造类型也足以使封闭的构造类型(我一度测试,那个我们呢堪测试一下、)。

泛型方法

泛型方法可在看似,结构,接口阐明中声称,那么些近似,结构,接口本身可以是泛型或者非泛型。

1.假如泛型方法以泛型类型中声称,则方法体可以又援引该方法的品种形参和寓该法的扬言(泛型类,结构,接口)的

  类型形参。

 2.类型形参可以视作重返路或者形参的路。

 
3.艺术的档次形参的名号不可知及同方法吃的家常形参的称号一致。

脚我对点的题材逐项说:

class A<T>

{

public static void Print<U, V>(U a, V b, T c)

{

Console.WriteLine(“{0}\n{1}\n{2}”, a.GetType(), b.GetType(), c.GetType());

}

}

class Test

{

public static void Main()

{

A<int>.Print<string, decimal>(“str”, 125.25m, 15);

Console.ReadKey();

}

}

本着承诺问题 1

 

class A

{

public static U Print<U, V>(U a, V b)

{

return a;

}

}

class Test

{

public static void Main()

{

Console.WriteLine( A.Print<string, byte>(“str”, 125));

Console.ReadKey();

}

}

 

针对许问题2

 

public static U Print<U, V>(U U, V b)尽管我们这里设置这么,语法没有错,可是编译器运行

时会指示:

 

错误 1

“U”: 参数或局部变量不可知及办法类型形参同名

对诺问题3

除此以外泛型方法除了非泛型方法的签署(由艺术的称与他的各国一个形参(按从左到右的相继)的种以及项目(值,引用,输出)组成。)要素外,泛型方法还连泛型类型形参的多少及种形参的序号地点按从左到右),记住前说过之档次形参只是单占位符。例如:

T F<T>(T a, int b)

{

return a;

}

void F (){ }

string F(string a,int b){};

}

地点的代码由于措施名相同,不过未会面报错,为啥吗,这就提到到点子的重载策略,然则只要出现:

public void F<U>(U a, int b) { },那么即使会面报错,因为这一点儿个泛型类型形参的数额及序列形参的序号地点都是均等的。假使自己当这样改一下:

public void F<U>(int b,U a )

重载策略的衍生,其实是同一的法则。

泛型委托

这边普通的泛型委托以及一般性委托同一大简单,我来尝试着测试一下匿名情势是勿是为同样简单好了。

public delegate T Degle<T>(int a, T b);

class Test

{

public static void Main()

{

Degle<string> dg = delegate(int a, string b)

{

return b;

};

Console.WriteLine(dg(125, “使用了匿名模式创立泛型委托”));

Console.ReadKey();

}

}

 

约束

于概念泛型类时,能够本着客户端代码可以以实例化类时用于项目参数的花色种类举办界定,倘使客户端代码使用某约束不允许的种来实例化类,就会来编译时左。这种限制称为约束。 约束是使

where 上下文关键字指定的。下表列出了六栽档次的格:

约束

说明

T:结构

类型参数必须是值类型。可以指定除 Nullable 以外的任何值

型。有关更多信息,请参见使用可空类型((C#C# 编程指南)。

T:类

类型参数必须是引用类型,包括任何类、接口、委托或数组型。

T:new()

类型参数必须具有无参数的公共构造函数 。当与其他约束一起用

用时,,new()new() 约束必须最后指定。

T:<基类名名>>

类型参数必须是指定的基类或派生自指定的基类。

T:<接口名称称>>

类型参数必须是指定的接口或实现指定的接口 。可以指定多个接

口约束。约束接口也可以是泛型的。

T:U

为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U

供的参数。这称为裸类型约束。

 

倘假定检泛型列表中的某个项为确定它们是否行得通,或者将它和此外有项举办比,则编译器必须在定水准上确保其要调用的运算符或形式将中客户端代码可能指定的别样项目参数的支撑。这种保证是经过对泛型类定义应用一个仍旧多单约束得到的。例如,基类约束告诉编译器:仅此类型的靶子要后种派生的对象才可用作类型参数。一旦编译器有矣这包,它便可以允许在泛型类中调用该种的点子。首先大家先行看一个(不以约束之)例子:

using System;

using System.Collections;

namespace Generic

{

public class Student

{

private string name;

public string Name

{

set

{

name = value;

}

get

{

return name;

}

}

public Student(string s)

{

name = s;

}

}

public class Grade<T> //定义一个年级类

ArrayList names = new ArrayList(10);

public void Add(T t)

{

names.Add(t.Name);//这里虽会拧

}

public void Display()

{

foreach (string s in names)

{

Console.WriteLine(s);

}

}

}

public class Test

{

public static void Main()

{

Grade<Student> gn = new Grade<Student>();

gn.Add(new Student(“小明”));

gn.Add(new Student(“小花”));

gn.Add(new Student(“阿猫”));

gn.Add(new Student(“阿狗”));

Console.WriteLine(“一年级的同校发:”);

gn.Display();

}

}

}

 

运转就晤面唤起:

错误 1

“T”不分包“Name”的概念,并且找不交然则领类型为“T”的首先个参数的扩充方法“Name”(是否缺 using 指令或程序集引用?)

 也就是说,大家在动用 T 为实在形参占位的上,编译器运行到names.Add(t.Name);

例到底有无发Name属性,或者这些Name到底是字段如故属性为?程序是同步一步走的,他一贯不丁之逻辑这样跳步完成有推理,所以这里就汇合报错,由此大家虽活该提前报告编译器这里类型形参T所可以表示的实际范围,这样尽管好化解问题了。因而这里虽引出了格来轻松的解决当下无异题目。我们特需要改一句子:public class Grade<T> where T:Student 我们当 Grade<T>的切近吃加进了自律,修改之后程序尽管可以就已通过,因为我们已经告诉编译器 Grade<T>的 T 是 Student 类或者派生自 Student 类的,所以可以接纳Stundent.Name 属性。

 usingSystem;

usingSystem.Collections;

namespaceGeneric

{

public class Student

{

private string name;

public string Name

{

set

{

name = value;

}

get

{

return name;

}

}

public Student(string s)

{

name = s;

}

}

public class Grade<T> where T:Student

{

ArrayList names = new ArrayList(10);

public void Add(T t)

{

names.Add(t.Name);//这里虽会出错

}

public void Display()

{

foreach (string s in names)

{

Console.WriteLine(s);

}

}

}

public class Test

{

public static void Main()

{

Grade<Student> gn = new Grade<Student>();

gn.Add(new Student(“小明”));

gn.Add(new Student(“小花”));

gn.Add(new Student(“阿猫”));

gn.Add(new Student(“阿狗”));

Console.WriteLine(“一年级的同班包括”);

gn.Display();

}

}

}

得对同品种的参数应用多单约束,并且封锁自身可以是泛型类型,例如:

public class Grade<T> where T:Student,IStudent,System.IComparable<T>,new()

{

//…

}

 

此地要一点底便是new(),new约束指定泛型类表明中之任何类型参数还必爆发集体的无参数构造函数。倘诺只要用new约束,则该类型不可能也架空类型。当泛型类成立项目标新实例,请将new约束应用被路参数,如下面的言传身教所示:

classItemFactory<T>where T :new()

{

public T GetNewItem()

{

return new T();

}

}

当与另外约束共同利用时,new() 约束必须最终指定:

publicclassItemFactory2<T>

where T : IComparable, new()

{

}

 通过自律类型参数,可以扩展约类型及其继承层次结构中的备类型所支撑之同意操作与办法调用的多寡。由此,在统筹泛型类依旧模式时,假设假定针对泛型成员举行除简单赋值之外的另外操作依旧调用System.Object 不补助的另外模式,您将待对拖欠档参数应用约束。

运用 where T : class 约束时,制止对品种参数使用 == 和 != 运算符,因为这个运算符仅测试引用同一性而无测试值相等性。即便以当参数的路中重载这些运算符也是如此。下边的代码表明了立即或多或少;即便 String 类重载 == 运算符,输出为为 false。

public static void OpTest<T>(T s, T t) where T : class

{

System.Console.WriteLine(s == t);

}

static void Main()

{

string s1 = “foo”;

System.Text.StringBuilder sb = new System.Text.StringBuilder(“foo”);

string s2 = sb.ToString();

OpTest<string>(s1, s2); //输出 false

}

这种场合的原委在,编译器在编译时止略知一二 T 是援引类型,由此要运用对持有援类型且使得的默认运算符。如若要测试值相等性,指出的措施是以用 where T : IComparable<T> 约束,并以将用来社团泛型类的旁类似吃贯彻该接口。

格两个参数

可针对大六只参数应用约束,并对一个参数应用五个框,如下边的示范所示:

class Base { }

class Test<T, U>

where U : structwhere T : Base, new() { }

勿绑定的色参数

从没约束之系列参数(如公共类 SampleClass<T>{} 中的 T)称为未绑定的类型参数。未绑定的门类参数有以下规则:不克用 = 和 == 运算符,因为不可能担保具体项目参数能帮助这么些运算符。可以以它们和 System.Object 之间来回换,或用她显式转换为外接口类型。可以拿其和 null 举行比。将未绑定的参数与 null 进行较时,假诺类型参数为值类型,则该于将总重返 false。

裸类型约束

 

当约束的泛型类型参数称为裸类型约束。当有友好之项目参数的分子函数必须用该参数约束为涵盖类型的花色参数时,裸类型约束非凡

用,如上面的示范所示:

class List<T>

{

void Add<U>(List<U> items) where U : T {/*…*/}

}

 

当下面的示范中,T 在 Add 方法的光景文中是一个裸类型约束,而当 List 类的前后文中是一个未绑定的门类参数。裸类型约束还足以在泛型类定义着以。注意,还须就与任何任何类型参数一起当尖括号丁声明了裸类型约束:

//naked type constraint

public class 萨姆(Sam)pleClass<T, U, V> where T : V { }泛型类的裸类型约束的功能好少,因为编译器除了要有裸类

品种约束派生自 System.Object 以外,不会师召开任何任何要。在盼强制两独品类参数之间的继续关系之动静下,可对泛型类以裸类型约束。

运泛型集合类

泛型最普遍的用途是泛型集合,从.NET2.0本类库开端提供一个新的命名空间 Sysstem.Collection.Generic,其中含了几乎单新的遵照泛型的集合类。使用泛型集合类可以供更强之品类安全性,在好几情况下还好供更好的特性,尤其是在蕴藏值类型时,这种优势还明确。

忆起一下常用的联谊类型

标题

说明

数组集合类型

描述可以让数组作为集合来进行处理的数组功能。

ArrayList 和

List 集合类型

描述泛型列表和非泛型列表(最常用的集合类型)的功能。

Hashtable 和

Dictionary 集 合

类型

描述基于哈希的泛型和非泛型字典类型的功能。

已排序的集合类型

描述提供列表和集的排序功能的类。

队列集合类型

描述泛型和非泛型队列的功能。

堆栈集合类型

描述泛型和非泛型堆栈的功能。

HashSet 集合类型

描述泛型 System.Collections.Generic.HashSet(OfT) 集合

类型。

HashSet 和 LINQ

Set 运算

描述 System.Collections.Generic.HashSet(OfT) 集合类型

提供的 Set 操作以及 LINQ Set 操作。

集合和数据结构

讨论 .NET Framework 中提供的各种集合类型,包括堆栈、队列、

列表、数组和结构。

.NET Framework

中的泛型

描述泛型功能,包括由 .NET Framework 提供的泛型集合、委托和

接口。 提供指向有关 C#、Visual Basic 和 Visual C++ 的功能

文档和支持技术(如反射)的链接。

 

常用的非泛型集合类及其相应的泛型集合类

 

ArrayList

List<T>

Hashtable

Dictionary<TKey,TValue>

Queue

Queue<T>

Stack

Stack<T>

SortedList

SortedList<T>

一般来说二种泛型集合类型没有对号入座之非泛型类型:

 

LinkedList 是一个通用的链接链表,它提供运算复杂呢 O(1)的插入和移除操作。

SortedDictionary 是一个排序的字典,其插入和摸索操作的演算复杂度为 O(log n),这如其成 SortedList 的卓殊可行之代表类

花色。KeyedCollection是在列表和字典里的夹类型,它提供了平栽存储包含自己拿手的对象的道。

貌似景色下,提出选用泛型集合,因为这样可以抱路安全之利而休待由集合类型派生并实现特定的成员。其它要集合素为值类型,泛型集合类型的性能一般优于对应之非泛型集合类型(并优化从非泛型集合类型派生的类型),因为运用泛型时不必元素进行装箱。对应的非泛型集合和泛型集合的功用相似基本相同,不过有泛型类型有在非泛型集合类型受到一贯不因而底效用。例如List<T>类(对使用非泛型ArrayList类)具有许多收受泛型委托(如许指定搜索列表的办法的Predicate委托、表示操作每个列元素的Action委托以及同意定义类型中变的Converter委托)的主意。List<T>类允许指定自己之用于排序和摸索列表的ICompare泛型接口实现。

下面看下List<T>和Dictionary<TKey,TValue>的程式代码:

using System;
using System.Collections.Generic;
namespace Generic_List
{
 class Test
 {
 static void Main(string[] args)
 {
 List<string> li =new List<string>();
 //与ArrayList一样默认容量大小为0,我在前方的章还涉嫌过ArrayList构造函数的功用问题
 //用法也基本均等
 Console.WriteLine(“Capacity:{0}\n”,li.Capacity);
 li.Add(“小沈阳”);
 li.Add(“赵本山”);
 li.Add(“陈佩斯”);
 li.Add(“柳岩”);
 foreach (string sin li)
 {
 Console.WriteLine(s);
 }
 Console.WriteLine(“Capacity:{0}\n Count:{1}”,li.Capacity,li.Count);
 Console.WriteLine(@”Contains(“”柳岩””) is {0}”, li.Contains(“柳岩”));
 Console.WriteLine(@”Insert(2,””宋丹丹””)”);
 li.Insert(2,”宋丹丹”);
 for (int i =0; i < li.Count; i++)
 {
 Console.WriteLine(li[i]);
 }
 Console.WriteLine(“Capacity:{0}\n Count:{1}”, li.Capacity, li.Count);
 Console.WriteLine(“Remove(\”陈佩斯\”)”);
 li.Remove(“陈佩斯”);
 foreach (string sin li)
 {
 Console.WriteLine(s);
 }
澳门总统娱乐, //这里大家再证实一下Capacity是否自动减多少,实际是false
 Console.WriteLine(“Capacity:{0}\n Count:{1}”, li.Capacity, li.Count);
 li.TrimExcess();//功用等价于ArrayList的TrimToSize
 Console.WriteLine(“使用TrimExcess函数后,Capacity={0}”,li.Capacity);
 Console.WriteLine(“使用Clear方法去所有因素”);
 li.Clear();
 Console.WriteLine(“Capacity:{0}\n Count:{1}”, li.Capacity, li.Count);
 Console.ReadKey();
 }
 }
}

//////////////////////////////////////////////////////////////////////////////

usingSystem;
usingSystem.Collections.Generic;

namespaceGeneric_Dictionary
{
 class Test
 {
 static void Main(string[] args)
 {
 Dictionary<string,string> doc =new Dictionary<string,string>();
 doc.Add(“操蛋曾某某”,”初中数学老师”);
 doc.Add(“蛋痛梁某”,”初中语文老师”);
 doc.Add(“无奈黄某”,”高中波兰语老师”);
 doc.Add(“邪恶徐某”,”无良缺德先生”);
 //如若试图添加一个都存在的工,Add方法会抛来一个坏
 try
 {
 doc.Add(“邪恶徐某”,”老师中之垃圾车”);
 }
 catch (ArgumentException)
 {
 Console.WriteLine(“已经在健->邪恶徐某”);
 }
 Console.WriteLine(“对应健->邪恶徐某的价值(描述)为:{0}”, doc[“邪恶徐某”]);
 //假诺使用索引器来赋值时,如若健已经存在,那么尽管会见窜对应之值,而无会晤掀起这一个
 doc[“邪恶徐某”] =”老师碰着的垃圾车”;
 Console.WriteLine(“对应健->邪恶徐某的值(描述)为:{0}”, doc[“邪恶徐某”]);
 //用索引器添加一个元素。
 doc[“xxxx”] =”大学老师”;
 try
 {
 Console.WriteLine(“对应doc[\”肖某\”]的值为:{0}”, doc[“肖某”]);
 }
 catch (KeyNotFoundException)
 {
 Console.WriteLine(“无对应值!”);
 }
 //当程序要平时尝试取字典中莫有的键值时,可以以TryGetValue方法
 //作为同一种更有效的检索值方法。
 string value =””;
 if (doc.TryGetValue(“ABC”,out value))
 {
 Console.WriteLine(“对应健\”ABC\”的值为{0}.”,value);
 }
 else
 {
 Console.WriteLine(“对应健\”ABC\”的价值不在”);
 }
 //插入元素前可以事先用ContainKey来判断健是否早已是
 if (!doc.ContainsKey(“ABC”))
 {
 doc.Add(“ABC”,”It’s a Test”);
 Console.WriteLine(“已经补给加了针对性应健\”ABC\”的值{0}\n”,doc[“ABC”]);
 }
 Console.WriteLine(“Remove(\”ABC\”)”);
 doc.Remove(“ABC”);
 if (!doc.ContainsKey(“ABC”))
 {
 Console.WriteLine(“没有找到ABC健”);
 }
 foreach (KeyValuePair<string,string> k_vin doc)
 {
 Console.WriteLine(“Key={0},Value={1}”,k_v.Key,k_v.Value);
 }
 //值的集
 Dictionary<string,string>.ValueCollection Vco = doc.Values;
 Console.WriteLine();
 foreach (string sin Vco)
 {
 Console.WriteLine(“Value={0}”,s);
 }
 //键的汇
 Dictionary<string,string>.KeyCollection Kco = doc.Keys;
 Console.WriteLine();
 foreach (string sin Kco)
 {
 Console.WriteLine(“Key={0}”, s);
 }
 Console.ReadKey();
 }
 }
}

 

打定义泛型集合类

同于定义的非泛型集合类一样,自定义泛型集合类也不可能不兑现System.Collection.Generic命名空间被之IEnumerable<T>和IEnummerator<T>

接口,由于IEnumerable<T>和IEnummerator<T>分别继承了IEnumerable和IEnummerator接口,由此,实现 IEnumerable<T>接口的近乎以,也必贯彻IEnumerable接口,实现IEnummerator<T>接口的类似以,也非得实现IEnummerator接口。

 usingSystem;
usingSystem.Collections.Generic;
usingSystem.Collections;

namespaceBookstore
{
 class store<T>:IEnumerable<T>,IEnumerator<T>
 {
 private string exceptionInfo =”索引无效,请保管调用了MoveNext”;
 private int index = -1;
 protected List<T> books;
 public store()
 {
 books=new List<T>() ;
 }
 public void Add(T book)
 {
 books.Add(book);
 }
 public void Remove(T book)
 {
 books.Remove(book);
 }
 //实现IEnumerator接口
 public bool MoveNext()
 {
 return(++index<books.Count);
 }
 public void Reset()
 {
 index = -1;
 }
 public T Current
 {
 get
 {
 if (0 <= index && index < books.Count)
 return books[index];
 else
 throw new IndexOutOfRangeException(exceptionInfo);
 }
 }
 //一般来说,非泛型的Current方法可概括的调用泛型Current方法
 object System.Collections.IEnumerator.Current
 {
 get
 {
 return Current;
 }
 }
 public IEnumerator<T> GetEnumerator()
 {
 Reset();
 return this;
 }
 //一般来说,非泛型的GetEnumerator方法可简简单单的调用泛型GetEnumerator方法
 IEnumerator System.Collections.IEnumerable.GetEnumerator()
 {
 return GetEnumerator();
 }
 public void Dispose()
 {
 }
 }
 class Test
 {
 static void Main(string[] args)
 {
 store<string> store =new store<string>();
 store.Add(“语文”);
 store.Add(“数学”);
 store.Add(“英语”);
 Console.WriteLine(“Store包含以下图书:”);
 foreach (string sin store)
 {
 Console.WriteLine(s);
 }
 Console.ReadKey();
 }
 }
}

 

泛型迭代器

跟非泛型迭代器唯一的别就是是,泛型迭代器的回到路必须是System.Collection.Generic.IEnumble<T>或者System.Collection.Generic.IEnumerator<T>,例如:

 usingSystem;
usingSystem.Collections.Generic;

namespaceGeneric_yield
{
 public class BookStore<T>
 {
 protected List<T> books;
 public BookStore()
 {
 books =new List<T>();
 }
 public void Add(T book)
 {
 books.Add(book);
 }
 public void Remove(T book)
 {
 books.Remove(book);
 }
 public IEnumerator<T> GetEnumerator()
 {
 foreach (T bookin books)
 {
 yield return book;
 }
 }
 }
 class Test
 {
 static void Main(string[] args)
 {
 BookStore<string> store =new BookStore<string>();
 store.Add(“语文”);
 store.Add(“数学”);
 store.Add(“英语”);
 Console.WriteLine(“Store包含以下图书:”);
 foreach (string sin store)
 {
 Console.WriteLine(s);
 }
 Console.ReadKey();
 }
 }
}

相关文章

网站地图xml地图