1 泛型结构

  结构和类同属于复合类型,可以有字段成员、方法成员和嵌套成员。同样,可以通过引入类型参数来定义泛型结构。泛型类的定义规则,包括类型限制、继承定义、构造类型的指定等,同样可以应用于泛型结构。二者之间的本质区别仍在于引用类型和值类型之间的差别。

  将MoreGenericSample程序进行修改,实现的功能类似。不同的是泛型类Relation<L,R>维护的只是一个数组,数组元素的类型则是泛型结构。

    class GenericStructSample{static void Main(string[] args){Relation<int, double> sinTable = new Relation<int, double>(180);for (int i = 0; i < 180; i++){sinTable.SetLeft(i,i);sinTable.SetRight(i,Math.Sin(Math.PI * i / 180));}//求正弦函数Console.WriteLine("请输入度数(0~179之间):");int x = int.Parse(Console.ReadLine());double y = sinTable.GetRight(x);Console.WriteLine("Sin({0}度)={1}", x, y);//求反正弦函数Console.WriteLine("请输入一个实数(0~1之间):");double r = double.Parse(Console.ReadLine());int pos;for (pos = 0; pos < sinTable.Length; pos++){if (Math.Abs(r-sinTable.GetRight(pos)) < 0.005){break;}}if (pos == sinTable.Length)Console.WriteLine("没有找到指定的反正弦值");elseConsole.WriteLine("arcsin({0})={1}度", r, sinTable.GetLeft(pos));}}/// <summary>/// 泛型结构:关联元素RelationElement/// </summary>public struct RelationElement<L,R>{//字段private L m_left;private R m_right;//属性public L Left{get{return m_left;}set{m_left = value;}}public R Right{get{return m_right;}set{m_right = value;}}//构造函数public RelationElement(L left, R right){m_left = left;m_right = right;}}/// <summary>/// 泛型类:关联Relation/// </summary>public class Relation<L,R>{//字段public RelationElement<L, R>[] m_list;//属性public int Length{get{return m_list.Length;}}//构造函数public Relation(int iLength){m_list = new RelationElement<L, R>[iLength];}//方法public L GetLeft(int index){return m_list[index].Left;}public R GetRight(int index){return m_list[index].Right;}public void SetLeft(int index,L left){m_list[index].Left=left;}public void SetRight(int index,R right){m_list[index].Right = right;}public int FindLeft(L left){for (int i = 0; i < Length; i++){if (m_list[i].Equals(left))return i;}return -1;}public int FindRight(R right){for (int i = 0; i < Length; i++){if (m_list[i].Equals(right))return i;}return -1;}}

View Code

2 泛型接口

2.1 泛型接口的定义

  泛型接口是比普通接口更为抽象的数据类型。和泛型类一样,可以为泛型接口指定一个或多个类型参数,也可以为类型参数添加类型限制。而泛型接口本身也可用于类型限制。例如:

public interface IOutput<T>{}
public interface IAssemble<T> where T:IComparable,IOutput<T>{}

  和泛型类类似,在类型限制的定义中,要求用于限制的接口要么是封闭类型,要么所含的类型参数在所定义的泛型接口的类型参数列表中出现。例如下面的代码是不合法的:

public interface IAssemble<T> where T : IOutput<U>{}//U未在IAssemble的定义中出现
public interface IAssemble<T> where T :IComparable,IOutput{}//IOutput类型不完整
public class Assemble<T> where T:IRelation<S,T>{}//S未在Assemble的定义中出现

  接口是抽象数据类型,它只可以有方法成员,而且只定义方法的标识而不提供方法的实现。

  泛型接口所定义的类型参数可以在其方法成员中作为参数或返回类型来使用。作为方法参数使用时,还可以是引用参数、输出参数和数组参数,例如:

public interface IRelation<L,R>
{int FindLeft(L left);int FindRight(R right);L GetLeft(int index);void GetRight(int index,out R right);void Change(ref L left,ref R right);
}

2.2 唯一性规则

  接口之间、类和接口之间可以是多继承的关系。引入了泛型接口之后问题就变得更为复杂。类可能是普通类,也可能是泛型类;泛型类可能是开放类型,也可能是封闭类型。接口也存在同样的情况,可能是普通接口,也可能是泛型接口;泛型接口可能是开放类型,也可能是封闭类型。但根本的原则没有变:开放类型不能从封闭类型中继承。当参与继承的双方都是泛型时,要求被继承的类型中的类型参数在派生类型的定义中出现。

  如果多个接口定义了相同的方法成员,其派生类既可以用一个成员方法来实现,也可以通过多个带接口声明的方法加以区分。例如:

public interface IA<S>
{void F();
}public interface IB<T>
{void F();
}public interface IRelation<L,R> : IA<L>,IB<R>
{new void F();
}public class IndexedAssemble<T> : IRelation<int,T>
{void IA<int>.F(){//
    }void IB<T>.F(){//
    } void IRelation<int,T>.F(){//
    }
}

  对于某个泛型接口,如果某个类或接口同时继承该泛型接口的多个构造类型,就可能导致同名的方法成员。例如下面的代码是错误的:

public class C<S,T> : IA<S>,IA<T>{}

  因为将来为泛型类C指定构造类型时,类型参数S和T可能被替换为同一种类型。例如C<int,int>,其中就会出现两个名为IA<int>.F的方法。

  下面的定义就是允许的:

public class C<T> : A<int,T>,B<T,string>{}

2.3 泛型接口与继承

  和泛型类一样,引入泛型接口的目的之一是为了在保留继承优越性的同时,避免频繁的类型转换。在很多情况下,只提供泛型类并不能完全解决这些问题。

  下面是一个完整的例子:

    class GenericInterfaceSample{static void Main(){IndexedAssemble<Contact> conAsm1 = new IndexedAssemble<Contact>(5);conAsm1.Right = new Business[5] {new Business("Mike Even"),new Business("李明"),new Business("David Gries"), new Business("张鹏"),new Business("White Brown")};IndexedAssemble<Contact> conAsm2 = new IndexedAssemble<Contact>(3);conAsm2.Right = new ClassMate[3]{new ClassMate("李明"),new ClassMate("Frank Douf"),new ClassMate("何子杰")};IndexedAssemble<Contact> conAsm = (IndexedAssemble<Contact>)conAsm1.Merge(conAsm2);//conAsm.Output();
            conAsm.Sort();conAsm.Output();}}/// <summary>/// 泛型接口:可合并IMerge/// </summary>public interface IMerge<T>{int Length { get; }T this[int index] { get; set; }IMerge<T> Merge(T tp);IMerge<T> Merge(IMerge<T> others);}/// <summary>/// 泛型类:关联Relation/// </summary>public class Relation<L,R>{//字段public L[] Left;public R[] Right;//属性public int Length{get{return Left.Length;}}//构造函数public Relation(int iLength){Left = new L[iLength];Right = new R[iLength];}//方法public int FindLeft(L left){for (int i = 0; i < Length; i++){if (Left[i].Equals(left))return i;}return -1;}public int FindRight(R right){for (int i = 0; i < Length; i++){if (Right[i].Equals(right))return i;}return -1;}}/// <summary>/// 泛型类:索引集合/// </summary>public class IndexedAssemble<T> : Relation<int,T>,IMerge<T> where T:IOutput,IComparable{//索引函数public T this[int index]{get{return Right[index];}set{Right[index] = value;}}//构造函数public IndexedAssemble(int iLength): base(iLength){for (int i = 0; i < Length; i++)Left[i] = i;}//方法public void Sort(){T tmp;for (int i=Length-1;i>0;i--){for(int j=0;j<i;j++){if(Right[Left[j]].CompareTo(Right[Left[j+1]])>0){tmp=Right[j+1];Right[j+1]=Right[j];Right[j]=tmp;}}}}public void Output(){for (int i = 0; i < Length; i++)Right[Left[i]].Output();}public IMerge<T> Merge(T tp){IndexedAssemble<T> result = new IndexedAssemble<T>(Length + 1);for(int i=0;i<Length;i++)result[i]=Right[i];result[Length]=tp;return result;}public IMerge<T> Merge(IMerge<T> others){IndexedAssemble<T> result = new IndexedAssemble<T>(Length + others.Length);for (int i = 0; i < this.Length; i++)result[i] = Right[i];for (int i = 0; i < others.Length; i++)result[this.Length + i] = others[i];return result;}}

View Code

  程序将合并之后的联系人按集合按Name属性的字母顺序输出:

商务:David Gries先生/女士
住宅电话:未知
办公电话:未知
手机:未知
商务传真:未知同学:Frank Douf
住宅电话:未知
办公电话:未知
手机:未知
生日:0001-1-1 0:00:00商务:Mike Even先生/女士
住宅电话:未知
办公电话:未知
手机:未知
商务传真:未知商务:White Brown先生/女士
住宅电话:未知
办公电话:未知
手机:未知
商务传真:未知同学:何子杰
住宅电话:未知
办公电话:未知
手机:未知
生日:0001-1-1 0:00:00商务:李明先生/女士
住宅电话:未知
办公电话:未知
手机:未知
商务传真:未知同学:李明
住宅电话:未知
办公电话:未知
手机:未知
生日:0001-1-1 0:00:00商务:张鹏先生/女士
住宅电话:未知
办公电话:未知
手机:未知
商务传真:未知请按任意键继续. . .

2.4 集合中的泛型

  第七章第3节中介绍过.NET类库中与集合相关的若干接口,不过他们的管理目标都是object类型。在引入了泛型接口后,就可以按特定的集合元素类型进集合进行管理了。

接口 支持的概念 继承的接口 主要方法
IEnumerator<T> 枚举器 bool MoveNext()
IEnumerable<T> 可列举的集合 IEnumerator<T>GetEnumerator()
ICollection<T> 有长度集合 IEnumerable<T> void CopyTo(T[],int)
void Add(T)
bool Remove(T)
void Clear()
IList<T> 可索引的对象列表 ICollection<T>,IEnumerable<T> void Insert(int,T)
int IndexOf(T)
void RemoveAt(int)
IComparable<T> 可比较的对象 int CompareTo(T)
bool Equals(T)
IComparer<T> 比较器 int CompareTo(T,T)
bool Equals<T,T>
int GetHashCode<T>
IDictionary<K,V> 有字典序的集合

ICollection<KeyValuePair<K,V>>,

IEnumerable<KeyValuePair<K,V>>

int Add(K,V)
bool Contains(K)
bool Remove(K)

  在第七章中,Contact类继承了IComparable接口,并实现了该方法,用于比较两个联系人对象姓名是否相等。

  方法中不可避免地涉及到了类型转换。如果改用泛型接口,使Contact类继承IComparable<Contact>接口就能避免这一问题。下面的程序实现了这一功能:

    class GenericCollectionSample{static void Main(){Contact c1 = new Business("Mike Even");Contact c2 = new Business("李明");Contact c3 = new ClassMate("David Gries");Contact c4 = new ClassMate("李明");Console.WriteLine("Mike Even(Business) < 李明(Business)?:{0}", c1.CompareTo(c2) < 0);Console.WriteLine("李明(Business)==李明(Classmate)?:{0}", c2 == c4);Console.WriteLine("李明(Business) Equals 李明(Classmate)?:{0}", c2.Equals(c4));}}/// <summary>/// 基类:联系人Contact/// </summary>public class Contact:IOutput,IComparable{//字段protected string m_name;protected string m_homePhone = "未知";protected string m_busiPhone = "未知";protected string m_mobilePhone = "未知";//属性public string Name{get{return m_name;}set{m_name = value;}}//虚拟索引函数public virtual string this[string sType]{get{string type = sType.ToUpper();switch (type){case "住宅电话":return m_homePhone;case "办公电话":return m_busiPhone;case "手机":return m_mobilePhone;default:return null;}}set{string type = sType.ToUpper();switch (type){case "住宅电话":m_homePhone = value;break;case "办公电话":m_busiPhone = value;break;case "手机":m_mobilePhone = value;break;default:throw new ArgumentOutOfRangeException();}}}//构造函数public Contact(string sName){m_name = sName;}//虚拟方法public virtual void Output(){Console.WriteLine("姓名:{0}", m_name);Console.WriteLine("住宅电话:{0}", m_homePhone);Console.WriteLine("办公电话:{0}", m_busiPhone);Console.WriteLine("手机:{0}", m_mobilePhone);Console.WriteLine();}//方法//public int CompareTo(Contact con)//{//    return this.m_name.CompareTo(con.m_name);//}public int CompareTo(object obj){if (obj is Contact)return this.m_name.CompareTo(((Contact)obj).m_name);return -1;}public bool Equals(Contact con){return this.Name.Equals(con.Name);}}/// <summary>/// 派生类:商务Business/// </summary>public class Business:Contact,IOutput{//字段protected string m_busiFax = "未知";protected string m_title = "先生/女士";//属性public string Title{get{return m_title;}set{m_title = value;}}//重载索引函数public override string this[string sType]{get{string type=sType.ToUpper();switch(type){case "商务传真":return m_busiFax;default:return base[sType];}}set{string type = sType.ToUpper();switch (type){case "商务传真":m_busiFax = value;break;default:base[sType] = value;break;}}}//构造函数public Business(string sName): base(sName){}//重载方法public override void Output(){Console.WriteLine("商务:{0}", m_name+m_title);Console.WriteLine("办公电话:{0}", m_busiPhone);Console.WriteLine("手机:{0}", m_mobilePhone);Console.WriteLine("商务传真:{0}", m_busiFax);Console.WriteLine();}//接口方法void IOutput.Output(){Console.WriteLine("商务:{0}", m_name + m_title);Console.WriteLine("住宅电话:{0}", m_homePhone);Console.WriteLine("办公电话:{0}", m_busiPhone);Console.WriteLine("手机:{0}", m_mobilePhone);Console.WriteLine("商务传真:{0}", m_busiFax);Console.WriteLine();}}/// <summary>/// 派生类:同学ClassMate/// </summary>public class ClassMate:Contact{//字段protected DateTime m_birthday;//属性public DateTime Birthday{get{return m_birthday;}set{m_birthday = value;}}//构造函数public ClassMate(string sName): base(sName){}//重载方法public override void Output(){Console.WriteLine("同学:{0}", m_name);Console.WriteLine("住宅电话:{0}", m_homePhone);Console.WriteLine("办公电话:{0}", m_busiPhone);Console.WriteLine("手机:{0}", m_mobilePhone);Console.WriteLine("生日:{0}", m_birthday.ToString());Console.WriteLine();}}

View Code

  注意,Contact类在继承泛型接口IComparable<T>(包括其构造类型)时,需要同时实现该接口的两个方法CompareTo和Equals。程序主方法中最后两行,分别使用了相等操作符和Equals方法来比较两个名为“李明”的对象,第一次比较的是二者是否指向同一个引用,而第二次则是调用Contact类的Equals方法来比较二者姓名是否相等。

  程序输出结果:

Mike Even(Business) < 李明(Business)?:True
Mike Even(Business) < David Gries(Classmate) ? : False
李明(Business)==李明(Classmate)?:False
李明(Business) Equals 李明(Classmate)?:True
请按任意键继续. . .

  将两个联系人集合合并的这程中可能会出现重复的对象。下面程序进行了修改,在出现重复时将只保留其中一个对象,而忽略掉其它多余的对象。

    class GenericImplementSample{static void Main(){IndexedAssemble<Contact> conAsm1 = new IndexedAssemble<Contact>(5);conAsm1.Right = new Business[5] {new Business("Mike Even"),new Business("李明"),new Business("David Gries"), new Business("张鹏"),new Business("White Brown")};IndexedAssemble<Contact> conAsm2 = new IndexedAssemble<Contact>(3);conAsm2.Right = new ClassMate[3]{new ClassMate("李明"),new ClassMate("Frank Douf"),new ClassMate("何子杰")};IndexedAssemble<Contact> conAsm = (IndexedAssemble<Contact>)conAsm1.Merge(conAsm2);//conAsm.Output();
            conAsm.Sort();conAsm.Output();}}/// <summary>/// 泛型类:关联Relation/// </summary>public class Relation<L,R> where R:IComparable{//字段public L[] Left;public R[] Right;//属性public int Length{get{return Left.Length;}}//构造函数public Relation(int iLength){Left = new L[iLength];Right = new R[iLength];}//方法public int FindLeft(L left){for (int i = 0; i < Length; i++){if (Left[i].Equals(left))return i;}return -1;}public int FindRight(R right){for (int i = 0; i < Length; i++){if (Right[i].Equals(right))return i;}return -1;}}/// <summary>/// 泛型类:索引集合/// </summary>public class IndexedAssemble<T> : Relation<int, T>, IMerge<T> where T : IOutput, IComparable{//索引函数public T this[int index]{get{return Right[index];}set{Right[index] = value;}}//构造函数public IndexedAssemble(int iLength): base(iLength){for (int i = 0; i < Length; i++)Left[i] = i;}//方法public void Sort(){T tmp;for (int i=Length-1;i>0;i--){for(int j=0;j<i;j++){if(Right[Left[j]].CompareTo(Right[Left[j+1]])>0){tmp=Right[j+1];Right[j+1]=Right[j];Right[j]=tmp;}}}}public void Output(){for (int i = 0; i < Length; i++)Right[Left[i]].Output();}public IMerge<T> Merge(T tp){if(this.FindRight(tp)!=-1)return this;IndexedAssemble<T> result = new IndexedAssemble<T>(Length + 1);for(int i=0;i<Length;i++)result[i]=Right[i];result[Length]=tp;return result;}public IMerge<T> Merge(IMerge<T> others){IMerge<T> result = this;for (int i = 0; i < others.Length; i++)result = result.Merge(others[i]);return result;}}

View Code

3 小结

  C#把泛型的优越性带到了整个类型系统当中,其中当然少不了泛型结构和泛型接口。泛型结构和泛型类非常类似,但它通常出现在需要值类型的场合。

  和普通接口一样,泛型接口是只有定义而不提供实现,但在接口继承特别是多继承的时候,要充分考虑泛型接口及其构造类型的区别,保持继承定义和方法实现的惟一性。

  泛型类和泛型接口能够共同实现算法与数据结构的抽象和分离。

转载于:https://www.cnblogs.com/boywg/p/4134522.html

第九章 泛型结构和接口相关推荐

  1. go var type 互转_Go语言学习笔记(第九章) 结构体

    Go语言基础之结构体 Go语言中没有"类"的概念,也不支持"类"的继承等面向对象的概念.Go 通过类型别名(alias types)和结构体的形式支持用户自定义 ...

  2. 第九章 Oracle结构及数据库表与开发语言的对应关系、Oracle数据类型char与varchar

    一,oracle结构及其与其他语言的交互关系

  3. 第九章 使用结构体类型处理组合数据——用户自定义数据类型

    9.1 定义和使用结构体变量 例9.1 把一个学生的信息放在一个结构体变量中,然后输出这个学生的信息. 程序代码如下: #include <stdio.h> int main() {str ...

  4. 第九章、结构体与共用体

    文章目录 9.1 结构体变量定义.引用.初始化 9.1.1 结构体概述 9.1.2 定义结构体类型变量的方法 9.1.3 结构体类型变量的引用 9.1.4 结构体变量的初始化 9.2 结构体数组.结构 ...

  5. 【疯狂Java讲义】第九章 泛型

  6. 第九章 泛型和枚举-枚举

    二.Java枚举Enum ​ 在某些情况下,一个类的对象的实例有限且固定的,如季节类,它只有春夏秋冬4个对象,再比如星期,在这种场景下我们可以使用枚举.当然我们也可以有自己的方法来实现. 方案一:静态 ...

  7. MySQL5.7-第九章语言结构

    第九章语言结构 目录 9.1文字值 9.1.1字符串文字 9.1.2数字文字 9.1.3日期和时间文字 9.1.4十六进制文字 9.1.5位值文字 9.1.6布尔文字 9.1.7空值 9.2架构对象名 ...

  8. Java编程思想第四版读书笔记——第九章 接口

    这章介绍了适配器设计模式和策略设计模式. 第九章  接口 接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法. 1.抽象类和抽象方法 public abstract void f(); 创 ...

  9. 第一章 计算机网络 5 分层结构/协议/接口/服务的概念 [计算机网络笔记]

    第一章 计算机网络 5 分层结构/协议/接口/服务的概念 本笔记参考书目: 计算机网络(第8版)谢希仁 2021王道计算机网络视频公开课 本节重点: 分层结构/协议/接口/服务 实体/对等实体 PCI ...

最新文章

  1. python3中的一些小改动
  2. Vue中使用v-for实现一对多数据的2层和3层嵌套循环
  3. sklearn模型的训练(上)
  4. [react] 除了实例的属性可以获取Context外哪些地方还能直接获取Context呢?
  5. Last_Error: Slave SQL thread retried transaction 10 time(s) in vain, giving up导致主从不同步的解决方法
  6. Gem5全系统FS(full system)测试
  7. selenium, firefox, python环境搭建指南
  8. 如何明晰定位与责任_公司股权决定公司决策,如何设计合理公司股权架构?
  9. 【Python】Python的urllib模、urllib2模块的网络下载文件
  10. jquery的autocomplete在firefox下不支持中文输入法的bug
  11. Linux基础介绍【第五篇】
  12. DotNet开发的微商分销系统源码,微信三级分销系统源码
  13. 37种传感器(四)之光敏电阻传感器模块+Stduino NanoUNO
  14. 多普勒微波感应和FMCW微波感应原理以及应用
  15. Function eregi is deprecated (解决方法)
  16. 云vr和传统vr_宣布我们的VR艺术家居住地
  17. ddr5和ddr4的区别 ddr5和ddr4性能差别
  18. gunicorn配置文件
  19. wps将word文档转换为图片格式
  20. 《OSPF和IS-IS详解》一1.7 独立且平等

热门文章

  1. 使用VS搭建三层结构
  2. 大数据之hadoop伪集群搭建与MapReduce编程入门
  3. Java内存管理的9个小技巧
  4. muduo之Thread
  5. linux进程的地址空间
  6. 位操作(Bit manipulation)
  7. LeetCode 78. 子集
  8. 开发者的实用 Vim 插件(一)
  9. wpf prism4 出现问题:无法加载一个或多个请求的类型。有关更多信息,请检索 LoaderExceptions 属性。...
  10. Web APi之过滤器执行过程原理解析【二】(十一)