当前位置:
首页 > 编程开发 > Objective-C编程 >
-
泛型-约束
制作者:剑锋冷月 单位:无忧统计网,www.51stat.net
9.5 约束
有的时候,您必须确保添加进泛型列表中的元素拥有某些约束(例如,它们从一个给定的基类继承或它们实现了指定的接口)。在下面的例子中,我们实现了一个简单的可排序的单链表。链表由多个Node组成,每个Node必须保证添加进去的元素实现了IComparer接口。您可以这样声明:
public class Node<T> : IComparable<Node<T>> where T : IComparable<T>
这句代码定义了一个泛型Node,它操作类型T。Node中的T实现了IComparable<T>接口,这意味着两个Node的T可以进行对比。Node类通过约束(where T : IComparable<T>)来操作那些实现了IComparable接口的类型。因此您可以使用任何类型来替代T,只要那种类型实现了IComparable接口
例9-12举例说明了完整的接口实现,并进行分析如下。
例9-12 使用约束
using System;
using System.Collections.Generic;
namespace UsingConstraints
{
public class Employee : IComparable<Employee>
{
private string name;
public Employee(string name)
{
this.name = name;
}
public override string ToString()
{
return this.name;
}
//实现接口
public int CompareTo(Employee rhs)
{
return this.name.CompareTo(rhs.name);
}
public bool Equals(Employee rhs)
{
return this.name == rhs.name;
}
}
//节点必须实现Node<T>的IComparable接口。
//通过where关键字约束Node只接收实现了IComparable接口的项
public class Node<T> : IComparable<Node<T>> where T : IComparable<T>
{
//成员变量
private T data;
private Node<T> next = null; //下一个节点
private Node<T> prev = null; //前一个节点
//构造方法
public Node(T data)
{
this.data = data;
}
//属性
public T Data
{
get { return this.data; }
}
public Node<T> Next
{
get { return this.next; }
}
public int CompareTo(Node<T> rhs)
{ //这样使用是因为约束
return data.CompareTo(rhs.data);
}
public bool Equals(Node<T> rhs)
{
return this.data.Equals(rhs.data);
}
//方法
public Node<T> Add(Node<T> newNode)
{ //下面的“我”代表类的当前实例
if (this.CompareTo(newNode) > 0) //小于我则放在我前面
{
newNode.next = this; //新节点的下一节点指向我
//如果我有前一个节点,则新节点的前一个节点指向它
//新节点做为它的下一个节点
if (this.prev != null)
{
this.prev.next = newNode;
newNode.prev = this.prev;
}
//设置我的前一个节点为新节点
this.prev = newNode;
//从下面的LinkedList<T>代码可以得知,添加都是从
//头节点开始判断,只有新节点为头节点时才返回它
return newNode;
}
else //大于等于我则放在我后面
{
//如果我有下一个,则跟下一个进行对比
//这里使用了递归,直到新节点找到比它大的节点为止
if (this.next != null)
{
this.next.Add(newNode);
}
//如果我没有下一个节点,则设置新节点为我的下一个
//节点,并把它的上一个节点指向我
else
{
this.next = newNode;
newNode.prev = this;
}
return this;
}
}
public override string ToString()
{
string output = data.ToString();
if (next != null)
{ //这里也使用了递归打印链表上的所有元素
output += ", " + next.ToString();
}
return output;
}
}
public class LinkedList<T> where T : IComparable<T>
{
//成员变量
private Node<T> headNode = null;
//索引器
public T this[int index]
{
get
{ //由于是链表,这里需要从头遍历
int ctr = 0;
Node<T> node = headNode;
while (node != null && ctr <= index)
{
if (ctr == index)
{
return node.Data;
}
else
{
node = node.Next;
}
++ctr;
}
throw new ArgumentOutOfRangeException();
}
}
//默认构造方法
public LinkedList()
{
}
//方法
public void Add(T data)
{
if (headNode == null)
{
headNode = new Node<T>(data);
}
else
{
headNode = headNode.Add(new Node<T>(data));
}
}
public override string ToString()
{
if (this.headNode != null)
{
return this.headNode.ToString();
}
else
{
return string.Empty;
}
}
}
//测试类
class Test
{
static void Main()
{ //创建一个实例来进行方法
Test t = new Test();
t.Run();
}
public void Run()
{
LinkedList<int> myLinkedList = new LinkedList<int>();
Random rand = new Random();
Console.Write("Adding: ");
for (int i = 0; i < 10; i++)
{
int nextInt = rand.Next(10);
Console.Write("{0} ", nextInt);
myLinkedList.Add(nextInt);
}
LinkedList<Employee> employees = new LinkedList<Employee>();
employees.Add(new Employee("John"));
employees.Add(new Employee("Paul"));
employees.Add(new Employee("George"));
employees.Add(new Employee("Ringo"));
Console.WriteLine("nRetrieving collections");
Console.WriteLine("Integers: " + myLinkedList);
Console.WriteLine("Employees: " + employees);
}
}
}
运行结果:
Adding:2 1 2 6 1 5 9 0 5
Retrieving collections…
Integers:0,1,1,1,2,2,5,5,6,9
Employees:George, John, Paul, Ringo
本例的开头声明了一个可以放到链表中的类:
public class Employee : IComparable<Employee>
这个声明指出Employee对象是可以进行对比的,可以看到Employee类实现了CompareTo和Equals方法。注意:这些方法是类型安全的(从参数传递进去的类是Employee类型)。LinkedList本身声明为只操作实现了IComparable接口的类型:
public class LinkedList<T> where T : IComparable<T>
这样就可以保证对列表进行排序。LinkedList操作Node类型的对象。Node也实现了IComparable接口,并要求它本身所操作的数据也实现了IComparable接口:
public class Node<T> : IComparable<Node<T>> where T : IComparable<T>
这些约束使得Node实现CompareTo方法变得安全而简单,因为Node知道它将和其它Node的数据进行对比:
public int CompareTo(Node<T> rhs)
{
// 这样使用是因为约束
return data.CompareTo(rhs.data);
}
注意,我们不需要测试rhs从而得知它是否实现了IComparable接口;我们已经约束了Node只能操作实现了IComparable接口的数据。
运行结果:
Adding:2 1 2 6 1 5 9 0 5
Retrieving collections…
Integers:0,1,1,1,2,2,5,5,6,9
Employees:George, John, Paul, Ringo
本例的开头声明了一个可以放到链表中的类:
public class Employee : IComparable<Employee>
这个声明指出Employee对象是可以进行对比的,可以看到Employee类实现了CompareTo和Equals方法。注意:这些方法是类型安全的(从参数传递进去的类是Employee类型)。LinkedList本身声明为只操作实现了IComparable接口的类型:
public class LinkedList<T> where T : IComparable<T>
这样就可以保证对列表进行排序。LinkedList操作Node类型的对象。Node也实现了IComparable接口,并要求它本身所操作的数据也实现了IComparable接口:
public class Node<T> : IComparable<Node<T>> where T : IComparable<T>
这些约束使得Node实现CompareTo方法变得安全而简单,因为Node知道它将和其它Node的数据进行对比:
public int CompareTo(Node<T> rhs)
{
// 这样使用是因为约束
return data.CompareTo(rhs.data);
}
注意,我们不需要测试rhs从而得知它是否实现了IComparable接口;我们已经约束了Node只能操作实现了IComparable接口的数据。
9.5 约束
有的时候,您必须确保添加进泛型列表中的元素拥有某些约束(例如,它们从一个给定的基类继承或它们实现了指定的接口)。在下面的例子中,我们实现了一个简单的可排序的单链表。链表由多个Node组成,每个Node必须保证添加进去的元素实现了IComparer接口。您可以这样声明:
public class Node<T> : IComparable<Node<T>> where T : IComparable<T>
这句代码定义了一个泛型Node,它操作类型T。Node中的T实现了IComparable<T>接口,这意味着两个Node的T可以进行对比。Node类通过约束(where T : IComparable<T>)来操作那些实现了IComparable接口的类型。因此您可以使用任何类型来替代T,只要那种类型实现了IComparable接口
例9-12举例说明了完整的接口实现,并进行分析如下。
例9-12 使用约束
using System;
using System.Collections.Generic;
namespace UsingConstraints
{
public class Employee : IComparable<Employee>
{
private string name;
public Employee(string name)
{
this.name = name;
}
public override string ToString()
{
return this.name;
}
//实现接口
public int CompareTo(Employee rhs)
{
return this.name.CompareTo(rhs.name);
}
public bool Equals(Employee rhs)
{
return this.name == rhs.name;
}
}
//节点必须实现Node<T>的IComparable接口。
//通过where关键字约束Node只接收实现了IComparable接口的项
public class Node<T> : IComparable<Node<T>> where T : IComparable<T>
{
//成员变量
private T data;
private Node<T> next = null; //下一个节点
private Node<T> prev = null; //前一个节点
//构造方法
public Node(T data)
{
this.data = data;
}
//属性
public T Data
{
get { return this.data; }
}
public Node<T> Next
{
get { return this.next; }
}
public int CompareTo(Node<T> rhs)
{ //这样使用是因为约束
return data.CompareTo(rhs.data);
}
public bool Equals(Node<T> rhs)
{
return this.data.Equals(rhs.data);
}
//方法
public Node<T> Add(Node<T> newNode)
{ //下面的“我”代表类的当前实例
if (this.CompareTo(newNode) > 0) //小于我则放在我前面
{
newNode.next = this; //新节点的下一节点指向我
//如果我有前一个节点,则新节点的前一个节点指向它
//新节点做为它的下一个节点
if (this.prev != null)
{
this.prev.next = newNode;
newNode.prev = this.prev;
}
//设置我的前一个节点为新节点
this.prev = newNode;
//从下面的LinkedList<T>代码可以得知,添加都是从
//头节点开始判断,只有新节点为头节点时才返回它
return newNode;
}
else //大于等于我则放在我后面
{
//如果我有下一个,则跟下一个进行对比
//这里使用了递归,直到新节点找到比它大的节点为止
if (this.next != null)
{
this.next.Add(newNode);
}
//如果我没有下一个节点,则设置新节点为我的下一个
//节点,并把它的上一个节点指向我
else
{
this.next = newNode;
newNode.prev = this;
}
return this;
}
}
public override string ToString()
{
string output = data.ToString();
if (next != null)
{ //这里也使用了递归打印链表上的所有元素
output += ", " + next.ToString();
}
return output;
}
}
public class LinkedList<T> where T : IComparable<T>
{
//成员变量
private Node<T> headNode = null;
//索引器
public T this[int index]
{
get
{ //由于是链表,这里需要从头遍历
int ctr = 0;
Node<T> node = headNode;
while (node != null && ctr <= index)
{
if (ctr == index)
{
return node.Data;
}
else
{
node = node.Next;
}
++ctr;
}
throw new ArgumentOutOfRangeException();
}
}
//默认构造方法
public LinkedList()
{
}
//方法
public void Add(T data)
{
if (headNode == null)
{
headNode = new Node<T>(data);
}
else
{
headNode = headNode.Add(new Node<T>(data));
}
}
public override string ToString()
{
if (this.headNode != null)
{
return this.headNode.ToString();
}
else
{
return string.Empty;
}
}
}
//测试类
class Test
{
static void Main()
{ //创建一个实例来进行方法
Test t = new Test();
t.Run();
}
public void Run()
{
LinkedList<int> myLinkedList = new LinkedList<int>();
Random rand = new Random();
Console.Write("Adding: ");
for (int i = 0; i < 10; i++)
{
int nextInt = rand.Next(10);
Console.Write("{0} ", nextInt);
myLinkedList.Add(nextInt);
}
LinkedList<Employee> employees = new LinkedList<Employee>();
employees.Add(new Employee("John"));
employees.Add(new Employee("Paul"));
employees.Add(new Employee("George"));
employees.Add(new Employee("Ringo"));
Console.WriteLine("nRetrieving collections");
Console.WriteLine("Integers: " + myLinkedList);
Console.WriteLine("Employees: " + employees);
}
}
}
运行结果:
Adding:2 1 2 6 1 5 9 0 5
Retrieving collections…
Integers:0,1,1,1,2,2,5,5,6,9
Employees:George, John, Paul, Ringo
本例的开头声明了一个可以放到链表中的类:
public class Employee : IComparable<Employee>
这个声明指出Employee对象是可以进行对比的,可以看到Employee类实现了CompareTo和Equals方法。注意:这些方法是类型安全的(从参数传递进去的类是Employee类型)。LinkedList本身声明为只操作实现了IComparable接口的类型:
public class LinkedList<T> where T : IComparable<T>
这样就可以保证对列表进行排序。LinkedList操作Node类型的对象。Node也实现了IComparable接口,并要求它本身所操作的数据也实现了IComparable接口:
public class Node<T> : IComparable<Node<T>> where T : IComparable<T>
这些约束使得Node实现CompareTo方法变得安全而简单,因为Node知道它将和其它Node的数据进行对比:
public int CompareTo(Node<T> rhs)
{
// 这样使用是因为约束
return data.CompareTo(rhs.data);
}
注意,我们不需要测试rhs从而得知它是否实现了IComparable接口;我们已经约束了Node只能操作实现了IComparable接口的数据。
运行结果:
Adding:2 1 2 6 1 5 9 0 5
Retrieving collections…
Integers:0,1,1,1,2,2,5,5,6,9
Employees:George, John, Paul, Ringo
本例的开头声明了一个可以放到链表中的类:
public class Employee : IComparable<Employee>
这个声明指出Employee对象是可以进行对比的,可以看到Employee类实现了CompareTo和Equals方法。注意:这些方法是类型安全的(从参数传递进去的类是Employee类型)。LinkedList本身声明为只操作实现了IComparable接口的类型:
public class LinkedList<T> where T : IComparable<T>
这样就可以保证对列表进行排序。LinkedList操作Node类型的对象。Node也实现了IComparable接口,并要求它本身所操作的数据也实现了IComparable接口:
public class Node<T> : IComparable<Node<T>> where T : IComparable<T>
这些约束使得Node实现CompareTo方法变得安全而简单,因为Node知道它将和其它Node的数据进行对比:
public int CompareTo(Node<T> rhs)
{
// 这样使用是因为约束
return data.CompareTo(rhs.data);
}
注意,我们不需要测试rhs从而得知它是否实现了IComparable接口;我们已经约束了Node只能操作实现了IComparable接口的数据。
最新更新
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
Python初学者友好丨详解参数传递类型
如何有效管理爬虫流量?
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
SQL Server -- 解决存储过程传入参数作为s
关于JS定时器的整理
JS中使用Promise.all控制所有的异步请求都完
js中字符串的方法
import-local执行流程与node模块路径解析流程
检测数据类型的四种方法
js中数组的方法,32种方法
前端操作方法
数据类型
window.localStorage.setItem 和 localStorage.setIte
如何完美解决前端数字计算精度丢失与数