惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
U
Unit 42
IT之家
IT之家
Y
Y Combinator Blog
T
Tailwind CSS Blog
B
Blog
大猫的无限游戏
大猫的无限游戏
博客园 - 叶小钗
Jina AI
Jina AI
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
I
InfoQ
J
Java Code Geeks
F
Fortinet All Blogs
T
The Blog of Author Tim Ferriss
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
H
Hackread – Cybersecurity News, Data Breaches, AI and More
人人都是产品经理
人人都是产品经理
腾讯CDC
Hugging Face - Blog
Hugging Face - Blog
GbyAI
GbyAI
博客园 - 司徒正美
The GitHub Blog
The GitHub Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
L
LangChain Blog

博客园 - Net_Learner

ASP.NET2.0 Provider模型(上) ——原理、模型与分析 浅析PetShop程序中的购物车和订单处理模块(Profile技术,异步MSMQ消息) PetShop数据库解读 petshop里的product.aspx页面详解 PetShop的工厂模式 PetShop之表示层设计 PetShop之业务逻辑层设计 PetShop之ASP.NET缓存 PetShop数据访问层之消息处理 PetShop数据访问层之数据库访问设计 PetShop的系统架构设计[转] Microsoft .NET Pet Shop 4 架构与技术分析 NET设计模式(3): 抽象工厂模式 NET设计模式(2): 工厂方法模式 NET设计模式(1): 简单工厂模式 七、用默认值初始化泛型变量 五、用泛型副本替换哈希表 四、List和LinkedList性能比较 三、用泛型替代ArrayList 二、理解泛型
六、泛型约束
Net_Learner · 2008-07-24 · via 博客园 - Net_Learner

问题:

你希望你的泛型类型在创建的时候必须有一个支持某个接口(比如IDisposable接口)成员的类型参数。

解决方法:

使用约束去强制泛型的类型参数实现某一个或多个特定的接口。

    public class DisposableList<T> : IList<T>   
        
where T : IDisposable
        
{
            
private List<T> _items = new List<T>();

            
// Private method that will dispose of items in the list
            private void Delete(T item)
            
{
                item.Dispose();
            }

        }

这个DisposableList类只允许实现了IDisposable接口的对象作为参数传递给它。那是因为,每次你从DisposableList对象中删除一个对象时,都要调用Dispose方法。这就使得你可以轻松管理DisposableList中的对象。

下面的代码就运用了DisposableList对象:

    public static void TestDisposableListCls() 
    
{    
        DisposableList
<StreamReader> dl = new DisposableList<StreamReader>();

        
// Create a few test objects.
        StreamReader tr1 = new StreamReader("c:\\boot.ini");
        StreamReader tr2 
= new StreamReader("c:\\autoexec.bat");
        StreamReader tr3 
= new StreamReader("c:\\config.sys");

        
// Add the test object to the DisposableList.
        dl.Add(tr1);
        dl.Insert(
0, tr2);
        dl.Add(tr3);

        
foreach(StreamReader sr in dl)
        
{
            Console.WriteLine(
"sr.ReadLine() == " + sr.ReadLine());
        }


        
// Call Dispose before any of the disposable objects are
        
// removed from the DisposableList.
        dl.RemoveAt(0);
        dl.Remove(tr1);
        dl.Clear();
    }

讨论:

Where关键字被用来约束类型参数只能接受那些满足给定约束的参数。比如,DisposableList有一个约束就是任何类型参数T必须实现IDisposable接口:

    public class DisposableList<T> : IList<T>
        
where T : IDisposable

这意味着,下面的代码将编译成功:

    DisposableList<StreamReader> dl = new DisposableList<StreamReader>();

但这个就不行了:

    DisposableList<string> dl = new DisposableList<string>();

这是因为string并没有实现IDisposable接口,而StreamReader实现了。

除了要求一个或多个接口被实现,其他对于类型参数的约束也是被允许的。你可以要求一个类型参数必须继承自一个特定的基类,比如Textreader类:

    public class DisposableList<T> : IList<T>
        
where T : System.IO.TextReader, IDisposable

你也可以约束这个类型参数只能是值类型或者只能是引用类型。下面声明的类的约束是其只能使用值类型:

    public class DisposableList<T> : IList<T>
        
where T : struct

而这个是只能使用引用类型:

    public class DisposableList<T> : IList<T>
        
where T : class

除此之外,你也可以要求任何类型参数去实现一个公共的默认构造函数:

    public class DisposableList<T> : IList<T>
        
where T : IDisposable, new()

使用约束使得你可以编写的泛型只能接受那些更具体的有用的参数类型。如果在这个示例中,IDsiposable约束被省略,那么一个编译时错误将会发生。这是因为,不是所有的类型它都可以被用作是实现了IDisposable接口的DisposableList类的参数的。如果你忽略这个编译时检查,一个DisposableList对象也许会包含那些并没有一个公共的无参数的Dispose方法的对象。在这种情况下,一个运行时异常将会发生。泛型和约束在一定程度上要求严格的参数类型检查,这使你在编译时就可以发现这些问题,而不是运行时。