现在的位置: 首页 > 综合 > 正文

C#泛型秘诀(6)

2012年08月10日 ⁄ 综合 ⁄ 共 3223字 ⁄ 字号 评论关闭
本系列文章翻译O'Reilly 出版的《C# Cookbook》一书中的片段,仅供学习交流使用

 

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

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

 

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

阅读参考

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


4.10 使用相应的泛型版本替换Hashtable

问题

您希望通过使用相应的泛型版本替换所有Hashtable来增强应用程序性能并使得代码更为易读。当您发现这些数据结构中存放结构体和值类型会导致装箱/拆箱操作,这就变得非常有必要了。

解决方案

替换所有已存在的System.Collections.Hashtable类为速度更快的System.Collections.Generic.Dictionary泛型类。

这有一个使用System.Collections.Hashtable对象的简单例子:

public static void UseNonGenericHashtable()
    
{
        
// 创建并填充一个Hashtable.
        Hashtable numbers = new Hashtable();
        numbers.Add(
1"one");    // 键会导致装箱操作
        numbers.Add(2"two");    // 键会导致装箱操作

        
// 在Hashtable显示所有的键/值对.
        
// 在每次迭代中都会因为键导致一个拆箱操作
        foreach (DictionaryEntry de in numbers)
        
{
            Console.WriteLine(
"Key: " + de.Key + "\tValue: " + de.Value);
        }

        numbers.Clear();
}

 

下面是相同的代码使用了System.Collections.Generic.Dictionary<T,U>对象:

public static void UseGenericDictionary()
    
{
        
// 创建并填充字典.
        Dictionary<intstring> numbers = new Dictionary<intstring>();
        numbers.Add(
1"one");
        numbers.Add(
2"two");
        
// 显示字典中的所有键值对.
        foreach (KeyValuePair<intstring> kvp in numbers)
        
{
            Console.WriteLine(
"Key: " + kvp.Key + "\tValue: " + kvp.Value);
        }

        numbers.Clear();
}

 

讨论

对于应用程序中简单的Hashtable实现,这种替换将十分容易。但有些地方需要注意,如泛型Dictionary类没有实现ICloneable接口,而Hashtable类实现了。

4-2显示了两个类中的等价成员:

4-2 Hashtable和泛型Dictionary类的等价成员

Hashtable 类的成员

泛型 Dictionary 类的相应成员

N/A

Comparer 属性

Count属性

Count属性

IsFixedSize属性

((IDictionary)myDict).IsFixedSize

IsReadOnly属性

((IDictionary)myDict).IsReadOnly

IsSynchronized属性

((IDictionary)myDict).IsSynchronized

Item属性

Item属性

Keys属性

Keys属性

SyncRoot属性

((IDictionary)myDict).SyncRoot

Values属性

Values属性

Add 方法

Add方法

Clear方法

Clear方法

Clone方法

在重载构造方法中接收一个 IDictionary<T,U> 类型

Contains方法

ContainsKey方法

ContainsKey方法

ContainsKey方法

ContainsValue方法

ContainsValue方法

CopyTo方法

抱歉!评论已关闭.