您的位置:首页 > 其它

用泛型实现参数化类型

2016-01-29 15:42 471 查看
泛型将大量安全检查从执行时转移到了编译时进行,泛型实现了类型和方法的参数化。

为什么需要泛型

将额外的信息作为方法或类型声明的一部分加以说明

IDE能基于额外的信息向程序员提供智能感知

方法调用者对自己传递的值和方法返回值更有把握

维护代码时,可以更好的掌握代码思路

日常使用的简单泛型
泛型字典

staticDictionary<string,int>CountWords(stringtext)

{

Dictionary<string,int>frequencies;

frequencies=newDictionary<string,int>();//创建从单词到频率的新映射

string[]words=Regex.Split(text,@"\w+");//将文本分解为单词

foreach(stringwordinwords)//添加或更新映射

{

if(frequencies.ContainsKey(word))

{

frequencies[word]++;

}

else

{

frequencies[word]=1;

}

}

returnfrequencies;


}


#region3—1,统计文本单词数

stringtext=@"DoyoulikegreemeggsandHam?Idonotlikethem,Sam-i-AM";

Dictionary<string,int>frequencies=CountWords(text);

foreach(KeyValuePair<string,int>entryinfrequencies)//打印映射中的每个键/值对

{

stringword=entry.Key;

intfrequency=entry.Value;

Console.WriteLine("{0}:{1}",word,frequency);

}

#endregion


泛型类型和类型参数

泛型两种形式:泛型类型(类,接口,委托,结构)和泛型方法
类型参数是真实类型的占位符。Dictionary<TKey,TValue>//TKey,TValue类型参数。Dictionary<string,int>//string,int类型实参
没有为泛型类型参数提供类型实参,那么就是一个未绑定泛型类型

如果指定了类型实参,就是一个已构造类型。已构造类型可以是开发或封闭的,开放类型还包括一个类型参数,封闭类型每个部分都是明确的
可以认为封闭类型拥有开放类型的API。
泛型方法和判读泛型声明


staticdoubleTakeSquareRoot(intx)//平方根3-2返回

{

returnMath.Sqrt(x);

}


#region3-2List<T>.ConcertAll<TOutput>

List<int>integer=newList<int>();//创建并填充整个列表

integer.Add(1);

integer.Add(2);

integer.Add(3);

integer.Add(4);

Converter<int,double>converter=TakeSquareRoot;//创建委托

List<double>doubles;

doubles=integer.ConvertAll<double>(converter);//调用泛型方法来转换列表

foreach(doubledindoubles)

{

Console.WriteLine(d);

}

#endregion


在非泛型方法中实现泛型方法

staticList<T>MakeList<T>(Tfirst,Tsecond)

{

List<T>list=newList<T>();

list.Add(first);

list.Add(second);

returnlist;

}


List<string>list=MakeList<string>("Line1","Line2");

List<string>list1=MakeList("Line1","Line2");//类型推断:只适用于泛型方法,不适用于泛型类型

Console.WriteLine(list.Capacity);

foreach(stringiinlist)

{

Console.WriteLine(i);

}


深化与提高

类型约束
类型参数可以被指定为任意类型时,它们未被约束
引用类型约束
确保使用的类型实参是引用类型。类型实参任何类,接口,委托,或已知是引用类型的另一个类型参数。

structTefSample1<T>whereT:class//引用类型约束,使用这种方式约束一个类型实参后,可以用==和!=来比较引用(包括NULL)

{


}


值类型约束

确保使用的类型实参是值类型,包括枚举,但是将可空类型排除在外

classTefSample<T>whereT:struct//值类型约束,使用这种方式约束一个类型实参后,不可以用==和!=来比较

{


}


构造函数类型约束

必须是所有类型参数的最后一个约束,它检查是否有一个可用创建类型实例的无参构造函数。所有值类型都有一个默认的无参构造函数,而且显示声明的构造函数和无参构造函数是用相同的语法来调用的。

publicstaticTCreateUbstance<T>()whereT:new()//检查类型实例是否有一个可用于创建类型实例的构造函数

{

returnnewT();

}


T为int和object都是有效的,但T为string是无效的,因为string没有一个无参构造函数

转换类型约束
可以规定一个类型实参必须可以转换成另一个类型实参

classSample<T>whereT:Stream//转换类型约束

{


}


Sample<Stream>s=newSample<Stream>();


组合约束

classSqmple<T,U>

whereT:class

whereU:struct,T//组合约束,每一个值类型都有一个构造函数,假如已经有了一个值类型约束,就不允许在有构造函数约束

{


}


//指定多个接口,但只能指定一个类

classSample2<T>whereT:Stream,IEnumerable<string>,IComparable<int>

{


}


泛型方法类型实参的类型推断

类型推断只适用于泛型方法,不适用于泛型类型

实现泛型
默认值表达式

//3-4将一个值与类型默认值比较

staticintCompaerToDefault<T>(Tvalue)whereT:IComparable<T>

{

returnvalue.CompareTo(default(T));

}


#region3-4以一个泛型方式将一个给定的值和一个默认值比较

Console.WriteLine(CompaerToDefault("x"));

Console.WriteLine(CompaerToDefault(10));

Console.WriteLine(CompaerToDefault(0));

Console.WriteLine(CompaerToDefault(-10));

Console.WriteLine(CompaerToDefault(DateTime.MinValue));

#endregion


直接比较

staticboolAreReferencesEqual<T>(Tfirst,Tsecond)whereT:class

{

returnfirst==second;

}


#region3-5用==和!=进行引用比较

stringname="Jon";

stringintro1="Mynameis"+name;

stringintro2="Mynameis"+name;

Console.WriteLine(intro1==intro2);

Console.WriteLine(AreReferencesEqual(intro1,intro2));

#endregion


对==进行重载,AreReferenxesEqual使用object

表示一对值

#region表示一对值的泛型类

publicsealedclassPair<T1,T2>:IEquatable<Pair<T1,T2>>

{

//每个封闭类型都有它自己的静态集

privatestaticreadonlyIEqualityComparer<T1>FirstComparer=EqualityComparer<T1>.Default;

privatestaticreadonlyIEqualityComparer<T2>SecondComparer=EqualityComparer<T2>.Default;


privatereadonlyT1first;

privatereadonlyT2second;


publicPair(T1first,T2second)

{

this.first=first;

this.second=second;

}


publicT1First{get{returnfirst;}}


publicT2Second{get{returnsecond;}}


publicboolEquals(Pair<T1,T2>other)

{

returnother!=null&&FirstComparer.Equals(this.First,other.First)&&SecondComparer.Equals(this.Second,other.Second);

}


publicoverrideboolEquals(objectobj)//重写

{

returnbase.Equals(objasPair<T1,T2>);

}


publicoverrideintGetHashCode()

{

returnFirstComparer.GetHashCode(first)*37+SecondComparer.GetHashCode(second);

}


}

#endregion


#region使用泛型方法的非泛型类型进行推断

publicstaticclassPair

{

publicstaticPair<T1,T2>Of<T1,T2>(T1first,T2second)

{

returnnewPair<T1,T2>(first,second);

}

}

#endregion


#region表示一对值的泛型类

Pair<int,string>pair=newPair<int,string>(10,"value");

#endregion


#region使用泛型方法的非泛型类型进行推断

Pair<int,string>pair1=Pair.Of(10,"VALUE");//类型推断根据方法进行,对于每一个方法实参,都尝试推断泛型方法的一些实参(简单推断技术),对于泛型方法要么推断要么全部显示指定。


#endregion


高级泛型

静态字段和静态构造函数
每个封闭的类型都有它自己的静态字段集

#region3-8证明不通的封闭类型具有不同的静态字段

//每个封闭类型有一个静态字段

TypeWithField<int>.field="First";

TypeWithField<string>.field="Secind";

TypeWithField<DateTime>.field="Third";


TypeWithField<int>.PrinfField();

TypeWithField<string>.PrinfField();

TypeWithField<DateTime>.PrinfField();

#endregion


classTypeWithField<T>

{

publicstaticstringfield;

publicstaticvoidPrinfField()

{

Console.WriteLine(field+":"+typeof(T).Name);

}

}


一个泛型类型可能嵌套在另一个泛型类型中,而且一个类型可能有多个泛型参数。

#region3-9嵌套泛型类型的静态构造函数

Outer<int>o=Outer.Of<int>();


Outer<int>.Inner<String,DateTime>.DummyMethod();

Outer<string>.Inner<int,int>.DummyMethod();

Outer<object>.Inner<string,object>.DummyMethod();

Outer<string>.Inner<string,object>.DummyMethod();

Outer<object>.Inner<object,string>.DummyMethod();

Outer<int>.Inner<string,DateTime>.DummyMethod();//任何封闭类型的构造函数只执行一次


#endregion


publicclassOuter<T>

{

publicclassInner<U,V>

{

staticInner()

{

Console.WriteLine("Outer<{0}>.Inner<{1},{2}>",

typeof(T).Name,

typeof(U).Name,

typeof(V).Name);

}

publicstaticvoidDummyMethod(){}

}

}


JIT编译器如果处理泛型

JIT为每个以值类型作为类型实参的封闭类型都创建不同的代码,所有使用引用类型作为类型实参的封闭类型都共享本地代码(所有引用都具有相同的大小。32位CLR上是4字节,64位CLR上是8字节)栈上一个引用所需空间始终相同。
ArrayList中,需要对每个字节进行装箱。



在32位CLR上:
ArrayList:8字节对象开销,4字节(1字节)数据本身,引用4字节
Liat<byte>:2字节(数据实际1字节)
泛型迭代
使用foreach,需要将集合的类型实参作为迭代变量类型使用

#region3-10

classCountingEnumerable:IEnumerable<int>

{

publicIEnumerator<int>GetEnumerator()//隐式实现IEnumerable<T>

{

returnnewCountingEnumerator();

}

IEnumeratorIEnumerable.GetEnumerator()//显示实现IEnumerable

{

returnGetEnumerator();

}


}


classCountingEnumerator:IEnumerator<int>

{

intcurrent=-1;


publicboolMoveNext()//接口IEnumerator的实现,将枚举数推进到集合的下一个元素。

{

current++;

returncurrent<10;

}


publicintCurrent{get{returncurrent;}}//隐式实现IEnumerator<T>.Current


objectIEnumerator.Current{get{returnCurrent;}}//显示实现IEnumerator.Current


publicvoidReset()//接口IEnumerator的实现,将枚举数设置为其初始位置,该位置位于集合中第一个元素之前。

{

current=-1;

}


publicvoidDispose(){}//接口IDisposable,执行与释放或重置非托管资源相关的应用程序定义的任务。

}

#endregion


#region3-10一个完整的泛型枚举

CountingEnumerablecounter=newCountingEnumerable();

foreach(intxincounter)//foreach会自动负责Dispose调用事项,用于结束迭代时释放资源

{

Console.WriteLine(x);

}

#endregion


反射和泛型

1.对泛型使用typeof
typeof可以通过两种方式作用于泛型类型——获取泛型定义和获取特定的构造函数

#region3-11对类型参数使用tupeof操作符

DemonstrateTypeof<int>();

#endregion


#region3-11

staticvoidDemonstrateTypeof<X>()

{

Console.WriteLine(typeof(X));//显示方法的类型参数


Console.WriteLine(typeof(List<>));//显示泛型类型

Console.WriteLine(typeof(Dictionary<,>));


Console.WriteLine(typeof(List<X>));//显示封闭类型(使用了类型参数)

Console.WriteLine(typeof(Dictionary<string,X>));


Console.WriteLine(typeof(List<long>));//显示封闭类型

Console.WriteLine(typeof(Dictionary<long,Guid>));


Console.WriteLine(typeof(Pair<,>));

Console.WriteLine(typeof(TypeWithField<>));

}

#endregion


在IL中,类型参数的数量是在框架所用的完整类型名称中指定的,在完整类型名称之后,会添加一个‘,然后是参数数量。

2.System。Type的属性和方法
任何特定的类型中有一个Type对象

#region获取泛型和以构造Type对象的各种方式

stringlistTypeName="System.Collections.Generic.List`1";//System.Collections.Generic.List`1


TypedefByName=Type.GetType(listTypeName);


TypeclosedByName=Type.GetType(listTypeName+"[System.String]");//将类型实参放入方括号中

TypecloseByMethod=defByName.MakeGenericType(typeof(string));

TypeclosedByTypeof=typeof(List<string>);


Console.WriteLine(closeByMethod==closedByName);

Console.WriteLine(closedByName==closedByTypeof);


TypedefByTypeof=typeof(List<>);

TypedefByMethod=closedByName.GetGenericTypeDefinition();


Console.WriteLine(defByMethod==defByName);

Console.WriteLine(defByName==defByTypeof);

#endregion


返回4次true
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: