C# - 常用接口
常用接口
用于比较接口
IComparable<T>
接口内部定义了用于比较两个对象大小的CompareTo(T t)方法,>参数时返回1,=参数时返回0,<参数时返回-1。集合类型的Sort方法的排序逻辑正是隐式地调用了此接口的CompareTo方法,Sort方法按CompareTo方法返回的值来确定应如何对元素进行排序,默认情况下是按从小到大进行排序。如果不喜欢使用此接口指定比较逻辑来排序,还可以直接使用Comparison<T>(T t1,T t2)委托,该委托作为Sort方法的参数被自动调用,你可以传递给Sort方法一个匹配Comparison<T>委托签名的lambda表达式用以指定比较的逻辑。
{
public int Score { get; set; }
//比较成绩
public int CompareTo(Student other)
{
return Score > other.Score ? 1 : Score < other.Score ? -1 : 0;
}
}
public class Programe
{
static void Main(string[] args)
{
Student stu1 = new Student { Score = 100 };
Student stu2 = new Student { Score = 90 };
int result=stu1.CompareTo(stu2);
Console.WriteLine(result); //print 1
}
}
IComparer<T>
接口内部定义了用于比较两个对象大小的Compare(T x, T y)方法,x>y时返回1,x=y时返回0,x<y返回-1。应创建一个新的类来实现此接口。集合类型的Sort方法可以排序逻辑可以接收IComparer的一个实例,Sort方法会自动调用该接口实例的Compare方法,Sort方法按Compare方法返回的值来确定应如何对元素进行排序。如果不喜欢使用此接口指定比较逻辑来排序,还可以直接使用Comparison<T>(T t1,T t2)委托,该委托作为Sort方法的参数被自动调用,你可以传递给Sort方法一个匹配Comparison<T>委托签名的lambda表达式用以指定比较的逻辑。
{
//比较成绩
public int Compare(Student x, Student y)
{
return x.Score > y.Score ? 1 : x.Score < y.Score ? -1 : 0;
}
}
public class Student
{
public int Score { get; set; }
}
public class Programe
{
static void Main(string[] args)
{
Student stu1 = new Student { Score = 100 };
Student stu2 = new Student { Score = 90 };
int result = new CompareObject().Compare(stu1, stu2);
Console.WriteLine(result); //print 1
}
}
用于测试相等性的比较接口
IEquatable<T>
接口内部定义了用于测试相等性的Equals(T other)方法。当前对象和参数对象相等则返回true,否则返回false。
{
public long Id { get; set; }
public string Name { get; set; }
public bool Equals(Employee other)
{
return other == null ? false : other.Name == Name ? true : false;
}
}
public class Programe
{
static void Main(string[] args)
{
var em = new Employee { Id = 1, Name = "sam" };
var em2 = new Employee { Id = 1, Name = "sam" };
Console.WriteLine(em.Equals(em2)); //print true
}
}
IEqualityComparer<T>
接口内部定义了用于测试相等性的Equals(T x , T y)方法和GetHashCode(T obj)方法。x和y相等则返回true,否则返回false。
如果想要两个版本的Equals()方法,比如一个用于测试两个对象的地址引用的相等性,另一个用于测试两个对象的属性的等同性,可考虑保持继承的Object的Equals()方法和GetHashCode()方法不变,然后通过实现IEqualityComparer<T>的Equals()和GetHashCode()来实现自定义的比较。如果需要将某个类型添加到泛型字典中,要么重写object的Equals()和GetHashCode(),要么实现IEqualityComparer<T>,这样就保持了两个版本的比较器,而要让泛型字典使用IEqualityComparer<T>的版本,则需要在初始化泛型字典时将实现IEqualityComparer<T>接口的类实例作为其构造函数的参数传递进去即可。如果没有传递这样的参数,则泛型字典将默认使用Object版本的Equals()和GetHashCode()。
{
public class Employee
{
public long Id { get; set; }
public string Name { get; set; }
}
public class EmployeesEqualName : IEqualityComparer<Employee>
{
public bool Equals(Employee x, Employee y)
{
return object.ReferenceEquals(x, y) ? true : x == null || y == null ? false : x.Name == y.Name ? true : false;
}
public int GetHashCode(Employee obj)
{
return obj.Name.GetHashCode();
}
}
public class Programe
{
static void Main(string[] args)
{
var em = new Employee { Id = 1, Name = "sam" };
var em2 = new Employee { Id = 1, Name = "sam" };
Console.WriteLine(new EmployeesEqualName().Equals(em, em2)); //print true
Dictionary<Employee, string> dictionarys = new Dictionary<Employee, string>(new EmployeesEqualName())
{
{ em,"1" },
{ em2,"2"}
};
Console.WriteLine(dictionarys.ContainsKey(em2));//抛出异常 因为属性值相等,em2不会作为key被添加
}
}
}
用于类型转换的接口
IConvertible<T>
接口内部定义了17个方法用于类型的强制转换,可实现自定义的转换规则。
用于泛型集合的接口
IEnumerable<T>
接口内部只有一个方法,这个方法叫做GetEnumerator(),该方法返回一个IEnumerator<T>实例,IEnumerator<T>称为枚举数。任何实现了IEnumerable<T>接口的类型都具有GetEnumerator()方法的实现,GetEnumerator()返回枚举数用于迭代。另外,Enumerable类为IEnumerable<T>扩展了几十个用于Linq查询的泛型扩展方法。实现了IEnumerable<T>的类型都能调用Linq查询。
IEnumerator<T>
接口内部定义了获取泛型集合中的当前元素、将指针移动到下一个元素、将指针归位的方法,所有实现了IEnumerable接口的泛型集合类型都通过实现其GetEnumerator()方法,该方法返回一个实现了迭代集合枚举数:IEnumerator实例,因为枚举的复杂度,C#已隐藏枚举的具体实现,建议通过foreach语句迭代集合元素。 最后注意,任何正在进行迭代的集合,都不要试图在这个过程中为集合执行添加、删除、修改操作,这些行为将被视为无效,如果修改值,编译器会提示错误,添加、删除不会提示错误,但这些行为是无效的。因为这样做会引起歧义,正在迭代当中却试图为集合执行增删改,那么枚举数就不知道接下来应该将改动视为一次迭代还是应忽视它们。
Current
//当前枚举中的元素
MoveNext()
//将枚举器的指针移动到下一个元素
Reset()
//将枚举器的指针归位,在索引0之前
内置的集合类型都可以使用for、foreach、集合.GetEnumerator()方法这三种方式迭代集合,但如果你要想让自定义的泛型集合也可以被迭代,你就必须手动实现IEnumerable<T>和IEnumerator<T>接口或者直接使用yied关键字
利用集合接口实现自定义泛型集合
自定义集合的初始化器
自定义一个公开的Add(Object obj)方法用于使集合初始化器可以正确添加项。下面是一个简陋的例子,只为说明如何为自定义集合添加初始化器:
{
public string Name { get; set; }
}
public class TestCollection : IEnumerable
{
public void Add(Animal a)
{
throw new NotImplementedException();
}
public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
}
TestCollection myLlist = new TestCollection
{
new Animal{ Name="sam" },
new Animal{ Name="korn" }
};
实现的步骤
1.定义支持集合初始化器的方法,一个Add(T obj)方法
2.实现IEnumerable<T>和IEnumerable接口,因为IEnumerable<T>派生自IEnumerable,有了这两个实现,就成功创建了表示集合的类型
3.定义支持通过索引获取项的索引器,有了索引器就可以使用for语句迭代每个项
4.创建一个可迭代的枚举器,必须实现IEnumerator<T>接口。有了可迭代的枚举器就可以使用IEnumerator的方法或foreach语句迭代每个项
{
public class Programe
{
public class Animal
{
public string Name { get; set; }
}
public class Aggregates<T> : IEnumerable<T>, IEnumerable
{
private List<T> Elms = new List<T>();
//集合的初始化器
public void Add(T t)
{
Elms.Add(t);
}
//索引器
public T this[int index]
{
get
{
return Elms.Any() ? index > (Elms.Count - 1) ? default(T) : Elms[index] : default(T);
}
set
{
if (Elms.Any())
{
if (index <= (Elms.Count - 1))
{
Elms[index] = value;
}
}
}
}
public IEnumerator<T> GetEnumerator()
{
return new AggregatesEnumerator<T>(Elms);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class AggregatesEnumerator<T> : IEnumerator<T>
{
public List<T> list;
private int indexer;
public T Current => list[indexer];
object IEnumerator.Current => list[indexer];
public AggregatesEnumerator(List<T> xAggregates)
{
list = xAggregates;
indexer = -1;
}
public void Dispose() { }
public bool MoveNext()
{
indexer++;
return indexer != list.Count();
}
public void Reset()
{
indexer = -1;//游标归位
}
}
static void Main(string[] args)
{
Aggregates<Animal> list = new Aggregates<Animal>
{
new Animal{ Name="sam" },
new Animal{ Name="korn" },
new Animal{ Name="landy" }
};
//IEnumerator迭代
var ItemRator = list.GetEnumerator();
while (ItemRator.MoveNext())
{
Console.WriteLine(ItemRator.Current.Name);
}
//foreach迭代
foreach (var item in list)
{
Console.WriteLine(item.Name);
}
//for迭代
for (int i = 0; i < list.Count(); i++)
{
Console.WriteLine(list[i].Name);
}
}
}
}
以上实现起始内部依然是通过将项存储在一个List<T>中,所以AggregatesEnumerator<T>类完全可以省略不写,然后在Aggregates<T>类的两个GetEnumerator()方法中直接返回List<T>的GetEnumerator()。
public IEnumerator<T> GetEnumerator ( )
{
return Elms.GetEnumerator ( );
} IEnumerator IEnumerable.GetEnumerator ( )
{
return GetEnumerator ( );
}
yield关键字
public IEnumerator<string> GetEnumerator ( )
{
yield return "leo"; //"运行时"会自动保存当前迭代的状态,下一次迭代时将根据被保存的迭代状态直接从上一次的位置向下移动一个项
yield return "sam";
yield return "korn";
yield return "landy";
}
public IEnumerator<T> GetEnumerator ( )
{
for ( int i = ; i < Elms.Count ; i++ )
{
yield return Elms [ i ];
}
}
//或:
public IEnumerator<T> GetEnumerator ( )
{
for ( int i = ; i < Elms.Count ; i++ )
{
if ( Elms [ i ] == null )
{
yield break; //取消当前迭代
}
yield return Elms [ i ];
}
}
yield return仅支持在返回IEnumerator<T>或IEnumerable<T>的方法中使用。如果需要实现倒序迭代,利用这个特点就可以定义一个Reverse的版本:
//倒叙迭代
public IEnumerable<T> GetReverseEnumerator ( )
{
for ( int i = Elms.Count - ; i >= ; i-- )
{
yield return Elms [ i ];
}
} foreach ( var item in 你的自定义的集合.GetReverseEnumerator ( ) )
{
Console.WriteLine ( item.Name );
}
IQueryable<T>
提供针对特定数据源评估查询的功能。IQueryable <T>同时派生自IEnumerable、IEnumerable<T>,IQueryable 。Enumerable类为IEnumerable<T>扩展了用于查询内存中的对象的linq查询方法。而Queryable为IQueryable <T>扩展了对远程数据源进行linq查询的方法。 IQueryable <T>有一个IQueryProvider(Linq查询提供程序)的属性,该属性通过解析扩展方法中的参数所指定的表达式树(Expression<Func<T>>)以便生成纯的SQL语句,IQueryProvider是一个可以自定义的Linq查询提供程序。Linq To Sql 和Linq To Entity都是查询数据库记录,必须生成Sql语句,这跟Linq To Object的查询不一样,后者只需要传入一个Func<T>(比如一个匹配Func<T>委托的Lambda表达式)就可以执行查询,而IQueryable <T的扩展方法需要你提供一棵表达式树(Expression<Func<T>>)以便IQueryProvider可以将表达式树解析为SQL查询字符串用于发送到数据库中执行远程查询。
ICollection<T>
Count
//获取项的总量
Add(T t)
//将参数添加到集合
Clear()
//从字典中移除所有的键和值
Contains(T t)
//确定集合是否包含参数指定的项
GetEnumerator()
//获取枚举数
Remove(T t)
//从集合中移除参数所指定的项
CopyTo(T[] TArray, int index)
//拷贝数组到参数指定的数组,可指定从哪个索引作为拷贝的起始位置。如果是引用类型则会发生一次浅拷贝,两个数组会指向同一个引用
实现了ICollection<T>接口的泛型集合
Queue<T>;
Stack<T>;
Dictionary<TKey, TValue>;
SortedList<TKey, TValue>;
IDictionary<TKey,TValue>
接口内部定义了泛型字典集合的属性与方法
Count
//获取项的总量
Keys
//获取键的集合
Values
//获取值的集合
Add(TKey, TValue)
//将指定的键和值添加到字典中
Clear()
//从字典中移除所有的键和值
ContainsKey(TKey)
//确定字典是否包含指定的键
ContainsValue(TValue)
//确定字典是否包含指定的值
Equals(object x)
//确定相等性
GetEnumerator()
//获取枚举数
GetHashCode()
//获取哈希值
GetObjectData(SerializationInfo info, StreamingContext context)
//实现System.Runtime.Serialization.ISerializable接口,并返回序列化Dictionary<TKey,TValue>实例所需的数据
Remove(TKey)
//从字典中移除键所指定的记录
IList<T>
接口内部定义了泛型列表集合的属性与方法
Count
//获取列表的项个数
Contains(T item)
//列表是否包含参数指定的元素
FindAll(Predicate<in T> match)
//根据泛型委托执行搜索
//示例:
var records = list.FindAll((employee) => (employee.Id | 1) != employee.Id); //Id是偶数的记录
BinarySearch(T item)
//使用二进制搜索查找元素,查不到返回-1,此方法与线性查找的效率相比,数据量大应采用BinarySearch,否则采用线性查找
CopyTo(T[] TArray, index)
//拷贝数组到参数指定的数组,可指定从哪个索引作为拷贝的起始位置。如果是引用类型则会发生一次浅拷贝,两个数组会指向同一个引用
Add(T item)
//向列表添加元素,数组没有实现这个方法,因为数组的长度是恒定的
Remove(T item)
//移除列表中由参数指定的元素,数组没有实现这个方法
RemoveAt(int index)
//移除列表中由参数指定的索引处的元素,数组没有实现这个方法
Insert(int index, T item)
//在参数指定的索引处插入一个新的元素,数组没有实现这个方法
Clear()
//清空列表,数组没有实现这个方法
泛型集合(Generic)
Dictionary<TKey,TValue> 哈希字典集合类
此类实现了IDictionary<TKey,TValue>接口,具体属性和方法参考IDictionary<TKey,TValue>。
SortedList<TKey,TValue> 可排序哈希字典集合类
此类实现了IDictionary<TKey,TValue>接口,表示一个可存储键值对的字典集合。它的性能不如Hashtable优异,因为集合的元素按照键进行了排序,所以可通过索引对元素进行访问。默认容量(capacity)是16,如果容量达到16则其容量会x2倍增。可通过重载的构造函数指定这个参数,也可通过添加元素使容量自动增长。
List<T> 列表集合类
此类实现了IList<T>接口,具体属性和方法参考IList<T>。
List<int> intList= list.ConvertAll(item => int.Parse(item)); //接收一个 Converter<in T, out X>的泛型委托,调用lambda将每次转换的结果返回给结果集
Stack<T> 栈集合类
此类实现了ICollection接口,它表示一个后进先出的栈集合,虽然元素有其索引,但因为元素压入之后只能从顶部取出,所以并不支持索引访问元素、也不支持初始化器。栈元素的插入称为入栈,元素的删除称为出栈。默认容量(capacity)是10,可通过重载的构造函数指定这个参数,也可以通过添加元素使容量自动增长。
stack.Push(new Person { Name = "sam" });
stack.Push(new Person { Name = "leo" });
stack.Push(new Person { Name = "korn" });
Console.WriteLine(stack.Count);
int[] intArray = { 1, 2, 3 };
Stack stack2 = new Stack(intArray);
Console.Write(stack.Peek()); // print 3
Queue<T> 单项队列集合类
此类实现了ICollection接口,表示一个先进先出的队列集合,虽然元素有其索引,但因为元素压入之后只能从右边出口取出,所以并不支持索引访问元素、也不支持初始化器。队列元素的插入称为入队,元素的删除称为出队。默认容量(capacity)是32,增量系数是2.0(growthFactor),如果容量达到32则其容量会x2倍增。可通过重载的构造函数指定这两个参数,也可以通过添加元素使容量自动增长。类似的有Queue<T>
C# - 常用接口的更多相关文章
- CSharpGL(2)设计和使用场景元素及常用接口
CSharpGL(2)设计和使用场景元素及常用接口 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码中包含10多个独立的Demo,更适合入 ...
- JDBC常用接口详解
JDBC中常用接口详解 ***DriverManager 第一.注册驱动 第一种方式:DriverManager.registerDriver(new com.mysql.jdbc.Driver()) ...
- Servlet API遍程常用接口和类
本文主要总结Servlet API遍程常用接口和类 Servlet API http://tomcat.apache.org/tomcat-5.5-doc/servletapi/index.html ...
- 液晶常用接口“LVDS、TTL、RSDS、TMDS”技术原理介绍
液晶常用接口“LVDS.TTL.RSDS.TMDS”技术原理介绍 1:Lvds Low-Voltage Differential Signaling 低压差分信号 1994年由美国国家半导体公司提出之 ...
- Java实战之02Hibernate-01简介、常用接口、CRUD操作
一.Hibernate简介 1.Hibernate在开发中所处的位置 2.ORM映射 Object :面向对象领域的 Relational:关系数据库领域的 Mapping:映射 Object: Re ...
- Hibernate常用接口
Hibernate的接口类型 在了解了Hibernate的基本配置,映射文件后,道路已经铺平了.我们继续往前走.接下来,我们应该做的是了解Hibernate常用的接口,对Hibernate的工作方式进 ...
- 【转】Android LCD(二):LCD常用接口原理篇
关键词:android LCD TFT TTL(RGB) LVDS EDP MIPI TTL-LVDS TTL-EDP 平台信息:内核:linux2.6/linux3.0系统:android/ ...
- JDBC数据库编程常用接口(转)
JDBC的全称是Java DataBase Connectivity,是一套面向对象的应用程序接口(API),制定了统一的访问各种关系数据库的标准接口,为各个数据库厂商提供了标准接口的实现.这东西能够 ...
- C# 常用接口学习 ICollection<T>
C# 常用接口学习 ICollection<T> 作者:乌龙哈里 时间:2015-11-01 平台:Window7 64bit,Visual Studio Community 2015 参 ...
- C# 常用接口学习 IComparable 和 IComparer
C# 常用接口学习 IComparable 和 IComparer 作者:乌龙哈里 时间:2015-11-01 平台:Window7 64bit,Visual Studio Community 201 ...
随机推荐
- React Router路由传参方式总结
首先我们要知道一个前提,路由传递的参数我们可以通过props里面的属性来获取.只要组件是被<Router>组件的<component>定义和指派的,这个组件自然就有了props ...
- zabbix源码安装 令人窒息的操作
一.简介 zabbix-server主要分为2部分: zabbix程序 程序根据客户端的监控项,从客户端获取数据并写入到数据库,再根据触发器/动作等配置进行操作. 展示页面 使用php编写,php脚本 ...
- Elasticsearch 通关教程(二): 索引映射Mapping问题
数据库建表的时候,我们的DDL语句一般都会指定每个字段的存储类型,例如:varchar,int,datetime等等,目的很明确,就是更精确的存储数据,防止数据类型格式混乱. CREATE TABLE ...
- CentOS自定义快捷键,以终端为例
和Ubuntu不同的是,CentOS默认情况下没有Terminal的快捷键.因此,用户需要自定义. 具体操作: 一.打开设置,搜索keyboard 二.点击+号定义快捷键 名称随意填,查询终端程序所在 ...
- Java的selenium代码随笔(3)
/** 以下方法主要用于切换页面*/public void SetPageSwitch(String pageTitle) {Set<String> allWindowsHandles = ...
- javascript高级排序算法之快速排序(快排)
javascript高级排序算法之快速排序(快排)我们之前讨论了javascript基本排序算法 冒泡排序 选择排序 插入排序 简单复习: 冒泡排序: 比较相邻的两个元素,如果前一个比后一个大,则交换 ...
- 根据字段获取DataTable包含某个值的数据
dt.Select("身份证号='" + list[i].PersonalId + "' and 培训完成日期 like '" + year + "% ...
- 02Lua入门
前言: 语言学起来其实相似点很多,简单整理的知识点 目录: 1.使用控制台 2.Lua基础 3.变量 4.运算符 5.控制结构 1.使用控制台 Lua脚本是包含一系列Lua命令的简单脚本(扩展名为.l ...
- 【转】如何在 GitHub 上找到你要的代码?
[来源]
- Codeforces 1082B Vova and Trophies(前缀+后缀)
题目链接:Vova and Trophies 题意:给定长度为n的字符串s,字符串中只有G和S,只允许最多一次操作:任意位置的两个字符互换.求连续G的最长长度. 题解:维护pre和pr,nxt和nx. ...