首页 > IT职业 > IT图书 > C#基础提升系列——C#集合
ArrayList、Queue、Hashtable等基类,包含定义对象的各种集合。List类可以使用Sort()方法对元素进行排序。Sort()方法有如下几个重载方法:
public void Sort(int index, int count, IComparer comparer);
public void Sort(Comparison comparison);
public void Sort();
public void Sort(IComparer comparer); 只有集合中的元素实现了IComparable接口,才能使用不带参数的Sort()方法。
如果需要按照元素类型 不 默认支持的方式排序,就需要使用其他重载方法,比如传递一个实现了IComparer接口的对象。
下面将用一个具体的示例进行说明:
public class Racer : IComparable
{
public int Id { get; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Country { get; set; }
public int Wins { get; set; }
//实现接口中的方法
public int CompareTo(Racer other)
{
int compare = LastName?.CompareTo(other?.LastName) ?? -1;
if (compare == 0)
{
return FirstName?.CompareTo(other?.FirstName) ?? -1;
}
return compare;
}
//定义构造函数
public Racer(int id, string firstName, string lastName, string country, int wins)
{
this.Id = id;
this.FirstName = firstName;
this.LastName = lastName;
this.Country = country;
this.Wins = wins;
}
//定义另一个构造函数,并调用上述构造函数
public Racer(int id, string firstName, string lastName, string country)
: this(id, firstName, lastName, country, wins: 0) { }
//重写object的Tostring()方法
public override string ToString()
{
return $"{FirstName} {LastName}";
}
} 上述的类直接实现了IComparable泛型接口,所以可以直接使用不带参数的Sort()方法进行排序,排序的依据基于重写的CompareTo()方法。
var racers = new List {
new Racer(1,"zhang","bsan","中国"),
new Racer(3,"li","asi","中国"),
new Racer(2,"wang","dwu","中国")
};
racers.Sort(); 执行上述语句,将会按照LastName进行排序后输出,依次为li asi、zhang bsan、wang dwu。
对上述示例进行扩展,使用传递一个实现了IComparer接口的对象进行排序。如下:
public class RacerComparer : IComparer
{
//定义一个枚举,可以直接通过类名.枚举名进行访问
public enum CompareType
{
FirstName,
LastName,
Country,
Wins
}
//定义枚举变量
private CompareType _compareType;
//定义构造函数,通过外部指定枚举类型
public RacerComparer(CompareType compareType)
{
_compareType = compareType;
}
//重写接口方法
public int Compare(Racer x, Racer y)
{
if (x == null && y == null) return 0;
if (x == null) return -1;
if (y == null) return 1;
int result;
switch (_compareType)
{
case CompareType.FirstName:
return string.Compare(x.FirstName, y.FirstName);
case CompareType.LastName:
return string.Compare(x.LastName, y.LastName);
case CompareType.Country:
result = string.Compare(x.Country, y.Country);
if (result == 0)
return string.Compare(x.LastName, y.LastName);
else return result;
case CompareType.Wins:
return x.Wins.CompareTo(y.Wins);
default:
throw new ArgumentException("Invalid Compare Type");
}
}
} 上述类RacerComparer 实现了泛型接口IComparer,其中泛型类型为Racer(实现IComparer接口中的泛型类型T应该是将要进行排序的元素的类型),并重写了Compare()方法,因此可以调用Srot(IComparer>)方法进行排序。
var racers = new List {
new Racer(1,"zhang","bsan","中国"),
new Racer(3,"li","asi","中国"),
new Racer(2,"wang","dwu","中国")
};
racers.Sort(new RacerComparer(RacerComparer.CompareType.FirstName));
//将会按照FirstName进行排序 还可以调用Sort(Comparison进行排序,Comparison是一个泛型委托,它的定义如下:
public delegate int Comparison(T x, T y); 它需要传入两个T类型的参数,返回类型为int。如果参数值相等,该方法返回0;如果第一个参数比第二个小,返回一个小于0的值;否则,返回一个大于0的值。
比如示例中如果按照Id进行排序,可以使用如下方法调用:
//由于是委托,此处可以使用lambda表达式
racers.Sort((r1, r2) => r1.Id.CompareTo(r2.Id)); 上述将会按照Id升序排序。
如果使用了Sort()进行排序后,可以调用Reverse()方法,逆转整个集合的排序。
可以调用
List集合的AsReadOnly()方法返回ReadOnlyCollection类型的对象。ReadOnlyCollection类实现的接口与List集合相同,除此之外还实现了IReadOnlyCollection和IReadOnlyList接口。因为这些接口的成员,集合不能修改。所有修改集合的方法和属性都抛出NotSupportedException异常。
public class ReadOnlyCollection : IList, ICollection, IEnumerable,
IEnumerable, IList, ICollection, IReadOnlyList, IReadOnlyCollection Dequeue() :删除并返回队列开头的元素。如果队列中没有元素,在调用该方法时,将会抛出一个InvalidOperationException类型的异常。 Enqueue(T) :将元素添加到队列的末尾。
Peek() :返回但不删除队列开头的元素。
TrimExcess() :如果该数量小于当前容量的90%,则将容量设置为队列的实际元素数。
Count :获取队列中的元素的个数
可以使用默认的构造函数创建一个空队列,也可以使用构造函数指定容量。在把元素添加到队列中时,如果没有指定容量,将会类似于List类,队列的容量也总是根据需要成倍增加,从而包含4、8、16和32个元素等。
下面将使用一个复杂的示例说明队列是如何使用的。首先定义一个简单的类:
public class Document
{
public string Title { get; }
public string Content { get; }
public Document(string title, string content)
{
this.Title = title;
this.Content = content;
}
} 接着为这个类进行队列写入和读取操作:
public class DocumentManager
{
private readonly Queue _documentQueue = new Queue();
//向队列中添加元素
public void AddDocument(Document doc)
{
//因为后面将要使用多线程,为了避免死锁,进行lock语句限制
lock (this)
{
_documentQueue.Enqueue(doc);
}
}
//获取队列中的元素
public Document GetDocument()
{
Document doc = null;
lock (this)
{
doc = _documentQueue.Dequeue();
}
return doc;
}
//队列中是否还有元素未读出
public bool IsDocumentAvailable => _documentQueue.Count > 0;
} 然后定义一个操作此类的对外开放的类:
public class ProcessDocuments
{
private DocumentManager _documentManager;
protected ProcessDocuments(DocumentManager dm)
{
_documentManager = dm ?? throw new ArgumentNullException(nameof(dm));
}
protected async Task Run()
{
while (true)
{
if (_documentManager.IsDocumentAvailable)
{
Document doc = _documentManager.GetDocument();
Console.WriteLine(doc.Title + ":" + doc.Content);
}
//显式的指定间隔时间,将会在此等待,从而执行该方法之外的代码部分
await Task.Delay(new Random().Next(1000));
}
}
//对外开放的调用方法
public static void Start(DocumentManager dm)
{
//启动一个新的任务
Task.Run(new ProcessDocuments(dm).Run);
}
} 调用代码如下:
public static void Run()
{
var dm = new DocumentManager();
ProcessDocuments.Start(dm);
for (int i = 0; i Pop() :删除并返回栈的顶部的一元素。如果栈没有元素,调用该方法将会抛出InvalidOperationException异常。 Push(T) :在栈的顶部插入一个元素。
Peek() :返回但不删除栈的顶部的一个元素。
Contains(T) :判断一个元素是否在栈中。
Count :返回栈中元素的个数。
下面使用一个简单的示例来说明栈的相关操作:
var mystacks = new Stack();
mystacks.Push(1);
mystacks.Push(2);
mystacks.Push(3);
foreach(var num in mystacks)
{
Console.Write(num+"t"); //将会输出:3 2 1
}
Console.WriteLine();
while (mystacks.Count > 0)
{
Console.Write(mystacks.Pop() + "t");
} 来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/1070/viewspace-2804010/ ,如需转载,请注明出处,否则将追究法律责任。