zoukankan      html  css  js  c++  java
  • C#编程(二十八)----------泛型类的功能

    泛型类的功能

    在创建泛型类时,还需要一些其他的C#关键字.例如,不能把null赋予泛型类型.此时,可以使用default关键字.如果泛型类型不需要object类的功能,但需要调用泛型类上的某些特定方法,就可以定义约束.

    例如:

    public class DocumentManager<T>

        {

            private readonly Queue<T> documentQueue = new Queue<T>();

            public void AddDocument(T doc)

            {

                lock (this)

                {

                    documentQueue.Enqueue(doc);

                }

            }

            public bool IsDocumentAvailable

            {

                get

                {

                    return documentQueue.Count > 0;

                }

            }

    }

    这是一个使用泛型文档福安里的实例.文档管理器用于从队列中读取文档.先创建一个新的控制台项目DocumentManager,并添加DocumentManager<T>.AddDocument()方法将一个文档添加到队列中.如果队列不为空,IsDocumentAvailable只读属性就返回true.

    默认值

    接下来给DocumentManager<T>类添加衣蛾GetDocument()方法.

     public T GetDocument()

            {

                T doc = default(T);

                lock (this)

                {

                    doc = documentQueue.Dequeue();

                }

                return doc;

            }

    在这个方法中,应该把类型T指定为null.但是不能把null赋予泛型类型.隐隐是泛型类型也可以实例化为值类型,null只能用于引用类型.为了解决这个问题,使用了default关键字,通过default关键字,null赋予引用类型,0赋予值类型.

    default关键字根据上下文可以有多重含义.switch语句使用default定义默认情况,在泛型中,根据泛型类型是引用类型还是值类型,泛型default用于将泛型类型初始化为null0.

    约束

    如果泛型类型需要调用泛型类型中的方法,就必须加以约束.对于DocumentManager<T>,文档的所在标题应在DisplayAllDocuments()方法显示.Document类实现带有TitleCOntent属性的IDocument接口:

    public interface IDocument

        {

            string Title { get; set; }

            string Content { get; set; }

        }

        public class Document : IDocument

        {

            public Document()

            {

            }

            public Document(string title, string content)

            {

                this.Title = title;

                this.Content = content;

            }

            public string Title { get; set; }

            public string Content { get; set; }

    }

    要使用DocumentManager<T>类显示文档,可以将类型T强制转换为IDocument接口,以显示标题:

     public void DisplayAllDocument()

            {

                foreach (T doc in documentQueue)

                {

                    Console.WriteLine(((IDocument)doc).Title);

                }

            }

    问题是,如果类型T没有实现IDocument接口,这个类型强制转换就会导致一个运行异常.最好给DocumentManager<TDocument>类定义一个约束:TDocument类型必须实现IDocument接口.为了在反省类型的名称中指定该要求,T改为TDocument.where子句指定了实现IDocument接口的要求.

    public class DocumentManager<TDocument>

    where TDocument : IDocument

    {}

    这样就可以编写foreach语句,从而使类型TDocument包含属性TItle. Visual Studio InterlliSense和编译器都会提供这个支持.

    public void DisplayAllDocument()

    {

    foreach (TDocument doc in documentQueue)

    {

    Console.WriteLine(doc.Title);

    }

    }

    main()方法中,Document类型实例化Documentmanager

    <T>,Document类型实现了需要IDocument接口.接着添加和显示新文档,检索其中一个文档:

    static void Main()

    {

    var dm= new Documentmanager<Document>();

    dm.AddDocument(new Document(“Title A”,”Sample A”));

    dm.AddDocument(new Document(“Title B”,”Sample B”));

    dm.DisplayAllDocument();

    if (dm.IsDocumentAvailable)

    {

    Document d=dm.GetDocument();

    Console.WriteLine(d.Content);

    }

    }

    DocumentManager现在可以处理任何实现了IDocument接口的类.

    在示例应用程序中,介绍了接口约束.泛型支持集中约束类型,如下表:

    约束

    说明

    where T :struct

    对于结构约束,类型T必须是值类型

    where T:class

    类约束制定类型T必须是引用类型

    where T:IFoo

    制定类型T必须实现接口IFoo

    whereT:Foo

    制定类型T必须派生自基类Foo

    whereT:new()

    这是一个构造函数约束,制定类型T必须有一个默认构造函数

    where T:T2

    这个约束也可以指定,类型T1派生自泛型类型T2.该约束也称为裸约束

    只有为默认构造函数定义构造函数约束,不能为其他构造函数定义构造函数约束.

    使用泛型类型还可以合并多个约束.where T:IFoo,new()约束和MyClass<T>声明指定,类型T必须实现IFoo接口,且必须有一个默认构造函数.

    public class MyClass<T>

    where T:IFoo,new()

    {

    //..

    }

    C#,where子句的一个重要限制是,不能定义必须由泛型类型实现的运算符.运算符不鞥在接口中定义.where子句中,只能定义基类,接口和默认构造函数.

    以上案例的完整代码:

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using System.Threading.Tasks;

    namespace ConsoleApplication9

    {

        class Program

        {

            static void Main(string[] args)

            {

                var dm = new DocumentManager<Document>();

                dm.AddDocument(new Document("Title A", "Sample A"));

                dm.AddDocument(new Document("Title B", "Sample B"));

                dm.DisplayAllDocument();

                if (dm.IsDocumentAvailable)

                {

                    Document d = dm.GetDocument();

                    Console.WriteLine(d.Content);

                }

                Console.ReadKey();

            }

        }

        public class DocumentManager<TDocument>

            where TDocument : IDocument

        {

            private readonly Queue<TDocument> documentQueue = new Queue<TDocument>();

            public void AddDocument(TDocument doc)

            {

                lock (this)

                {

                    documentQueue.Enqueue(doc);

                }

            }

            public bool IsDocumentAvailable

            {

                get

                {

                    return documentQueue.Count > 0;

                }

            }

            public TDocument GetDocument()

            {

                TDocument doc = default(TDocument);

                lock (this)

                {

                    doc = documentQueue.Dequeue();

                }

                return doc;

            }

            public void DisplayAllDocument()

            {

                foreach (TDocument doc in documentQueue)

                {

                    Console.WriteLine(doc.Title);

                }

            }

        }

        public interface IDocument

        {

            string Title { get; set; }

            string Content { get; set; }

        }

        public class Document : IDocument

        {

            public Document()

            {

            }

            public Document(string title, string content)

            {

                this.Title = title;

                this.Content = content;

            }

            public string Title { get; set; }

            public string Content { get; set; }

        }

    }

    继承

    前面创建的LinkedList<T>类实现了IEnumerable<out T>接口:

    public class LinkedList<T>:IEnumerable<out T>

    {

    //...

    }

    泛型类型可以实现泛型接口,也可以派生自一个类.泛型类还可以派生自泛型基类:

    public class Base<T>

    {

    }

    public class Derived<T>:Base<T>

    {}

    要求是必须重复接口的泛型类型,或者必须制定基类的类型,:

    public class Base<T>

    {

    }

    public class Derived<T>:Base<string>

    {}

    于是,派生类可以是泛型类或者非泛型类.例如,可以定义一个抽象的泛型基类,它在派生类中用一个具体的类型实现.这允许对特定类型执行特殊的操作:

    public abstract class Calc<T>

        {

            public abstract T Add(T x, T y);

            public abstract T Sub(T x, T y);

        }

        public class IntCalc : Calc<int>

        {

            public override int Add(int x, int y)

            {

                return x + y;

            }

            public override int Sub(int x, int y)

            {

                return x - y;

            }

        }

    静态成员

    泛型类的静态成员需要特别关注.泛型类的景天成员只能在类的一个实例中共享.看下例,其中StaticDemo<T>类包含静态字段x:

      public class StaticDemo<T>

        {

            public static int x;

    }

    Main()函数中的代码如下:

    static void Main(string[] args)

            {

                StaticDemo<string>.x = 4;

                StaticDemo<int>.x = 5;

                Console.WriteLine(StaticDemo<string>.x);

                Console.ReadKey();

            }

    由于同时对一个string类型和一个int类型使用了StaticDemo<T>,所以存在两组静态类型.

  • 相关阅读:
    tensorflow2.0 GPU和CPU 时间对比
    第一次使用FileZilla Server
    PremiumSoft Navicat 15 for Oracle中文破解版安装教程
    Unmapped Spring configuration files found. Please configure Spring facet or use 'Create Default Context' to add one including all unmapped files.
    ng : 无法加载文件 D: odejs ode_global g.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID=135170 中的 about_Execution_Policies。
    angular
    Github上优秀的go项目
    win10---file explore 中remove quick access folder
    react--useEffect使用
    linux---cat 和 grep 的妙用
  • 原文地址:https://www.cnblogs.com/android-blogs/p/6593109.html
Copyright © 2011-2022 走看看