C#泛型秘诀(6)

4.9 使用泛型创建只读集合

问题

您希望类中的一个集合里的信息可以被外界访问,但不希望用户改变这个集合。

解决方案

使用ReadOnlyCollection<T>包装就很容易实现只读的集合类。例子如,Lottery类包含了中奖号码,它可以被访问,但不允许被改变:

public class Lottery
  {
    // 创建一个列表.
    List<int> _numbers = null;
    public Lottery()
    {
      // 初始化内部列表
      _numbers = new List<int>(5);
      // 添加值
      _numbers.Add(17);
      _numbers.Add(21);
      _numbers.Add(32);
      _numbers.Add(44);
      _numbers.Add(58);
    }
    public ReadOnlyCollection<int> Results
    {
      // 返回一份包装后的结果
      get { return new ReadOnlyCollection<int>(_numbers); }
    }
}

Lottery有一个内部的List<int>,它包含了在构造方法中被填的中奖号码。有趣的部分是它有一个公有属性叫Results,通过返回的ReadOnlyCollection<int>类型可以看到其中的中奖号码,从而使用户通过返回的实例来使用它。

如果用户试图设置集合中的一个值,将引发一个编译错误:

Lottery tryYourLuck = new Lottery();
  // 打印结果.
  for (int i = 0; i < tryYourLuck.Results.Count; i++)
  {
    Console.WriteLine("Lottery Number " + i + " is " + tryYourLuck.Results[i]);
  }
  // 改变中奖号码!
  tryYourLuck.Results[0]=29;
  //最后一行引发错误:// Error 26 // Property or indexer
  // 'System.Collections.ObjectModel.ReadOnlyCollection<int>.this[int]'
  // cannot be assigned to -- it is read only

讨论

ReadOnlyCollection的主要优势是使用上的灵活性,可以在任何支持IList或IList<T>的集合中把它做为接口使用。ReadOnlyCollection还可以象这样包装一般数组:

int [] items = new int[3];
  items[0]=0;
  items[1]=1;
  items[2]=2;
new ReadOnlyCollection<int>(items);

这为类的只读属性的标准化提供了一种方法,并使得类库使用人员习惯于这种简单的只读属性返回类型。

阅读参考

查看MSDN文档中的“IList”和“Generic IList”主题。

时间: 2024-12-31 19:39:00

C#泛型秘诀(6)的相关文章

C#泛型秘诀(8完)

4.13 初始化泛型变量为它们的默认值 问题 您的泛型类包含一个变量,它的类型和类中定义的类型参数一样.在构造泛型类时,您希望这个变量被初始化为它的默认值. 解决方案 简单地使用default关键字把变量初始化为它的默认值: public class DefaultValueExample<T> { T data = default(T); public bool IsDefaultData() { T temp = default(T); if (temp.Equals(data)) { r

C#泛型秘诀(2)

4.3 获取泛型的类型 问题 您需要在运行时获得一个泛型类型实例的Type对象. 解决方案 在使用typeof操作符时提供类型参数:使用类型参数实例化的泛型类型,用GetType()方法. 声明一个一般类型和一个泛型类型如下: public class Simple { public Simple() { } } public class SimpleGeneric<T> { public SimpleGeneric() { } } 使用typeof操作符和简单类型的名称就可以在运行时获得简单

C#泛型秘诀(1)

4.0 介绍 泛型,一个期待已久的功能,随着C# 2.0版本编译器的到来最终出现.泛型是一个非常有用的功能,它使得您的代码变得精简而富有效率.这些将在秘诀4.1进行详细讲述.泛型的到来使得您可以编写更为强大的应用程序,但这需要正确地使用它.如果您考虑把ArrayList,Queue,Stack和Hashtable对象转变为使用相应的泛型版本,可以阅读秘诀4.4,4.5和4.10.当您阅读过后,会发现这种转变不一定简单,甚至有可能会不再打算进行转变. 本章的另外一些秘诀涉及到.NET Framew

C#泛型秘诀(7)

4.11 在泛型字典类中使用foreach 问题 您希望在实现了System. Collections.Generic.IDictionary接口的类型枚举元素,如System.Collections.Generic.Dictionary 或 System.Collections.Generic.SortedList. 解决方案 最简单的方法是在foreach循环中使用KeyValuePair结构体: // 创建字典对象并填充. Dictionary<int, string> myString

C#泛型秘诀(5.1)

4.8 反转Sorted List里的内容 问题 您希望在数组和列表类型中可以反转sorted list里的内容同时又维持SortedList和SortedList<T>类原来的功能.无论是SortedList还是泛型SortedList<T>类都直接提供了完成这个功能的方法而又不需要重填列表. 解决方案 ReversibleSortedList<TKey, TValue>类提供了这些功能,它基于SortedList<TKey, TValue>类,所以拥有相

C#泛型秘诀(4)

4.6 链表的实现 问题 您需要链表数据结构,这样就可以很容易地添加和删除元素. 解决方案 使用泛型LinkedList<T>类.下面的方法创建了一个LinkedList<T>类,并往链表对象中添加节点,然后使用了几种方法从链表节点中获得信息. public static void UseLinkedList() { // 创建一个LinkedList 对象. LinkedList<TodoItem> todoList = new LinkedList<TodoI

C#泛型秘诀(3)

4.5 使用相应的泛型版本替换Stack和Queue 问题 您希望通过将所有Stack和Queue对象替换为相应的泛型版本以提高应用程序的效率,并使得代码更易于使用.当结构体或其他值类型存储在这些数据结构中时,会导致装箱/拆箱操作,这时就需要这么做. 解决方案 使用System.Collections.Generic.Stack和System.Collections.Generic.Queue对象来替换现有的System.Collections.Stack和System.Collections.

C#泛型秘诀(5.3)

Nested Types#region Nested Types Enumerator K, V#region Enumerator <K, V> [Serializable, StructLayout(LayoutKind.Sequential)] private struct Enumerator<K, V> : IEnumerator<KeyValuePair<K, V>>, IDisposable, IDictionaryEnumerator, IE

C#泛型秘诀(5.2)

私有方法#region 私有方法 private void EnsureCapacity(int min) { int num1 = (this.keys.Length == 0) ? 4 : (this.keys.Length * 2); if (num1 < min) { num1 = min; } this.InternalSetCapacity(num1, false); } //返回指定索引的值 private TValue GetByIndex(int index) { if ((i