c# 泛型

本文介绍如何使用泛型创建链表,以及在委托和接口中使用协变与逆变的概念。探讨了不同类型的约束,包括主要约束、次要约束及构造器约束。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

封闭类型才能创建实例,开放类型不能创建实例;

每个封闭类型都有自己的静态字段;

 

通过泛型实现一个链表:

    //链表基类
    internal class Node
    {
        protected Node m_next;
        public Node(Node next)
        {
            this.m_next = next;
        }
    }
    //链表派生类
    internal class NodeType<T>: Node
    {
        public T m_data;
        public NodeType(T data): this(data, null)
        {

        }

        public NodeType(T data, Node next) : base(next)
        {
            this.m_data = data;
        }

        public override string ToString()
        {
            return this.m_data.ToString() + ((this.m_next != null) ? this.m_next.ToString() : String.Empty);
        }
    }

 

委托和接口泛型中的逆变和协变

不变量: 意味着泛型类型参数不能更改。

逆变量: 意味着泛型类型参数可以从一个类更改为它的某个派生类。在C#是用in关键字标记逆变量形式的泛型类型参数。逆变量泛型类型参数只出现在输入位置,比如作为方法的参数。

协变量: 意味着泛型类型参数可以从一个类更改为它的某个基类。C#是用out关键字标记协变量形式的泛型类型参数。协变量泛型类型参数只能出现在输出位置,比如作为方法的返回类型。

例如:

            Func<Object, ArgumentException> fn1 = null;
            Func<string, Exception> fn2 = fn1;

        是能够成立的。因为fn1变量引用一个方法,获取一个Object,返回一个ArgumentException。而fn2变量引用另一个方法,获取一个String,返回一个Exception。由于可将一个String传给期待Object的方法(因为String从Object派生),而且由于可以获取返回ArgumentException的一个方法的结构,并将这个结构当成一个Exception(因为Exception 是 ArgumentException 的基类),所以上述代码能正常编译。

 

可验证性和约束

        private static T Min<T>(T o1, T o2) where T : IComparable<T>
        {
            if (o1.CompareTo(o2) < 0)
            {
                return o1;
            }
            return o2;
        }

        where关键字告诉编译器,为T指定的任何类型都必须实现同类型(T)的泛型IComparable<T>接口。

        约束可用于泛型类型的类型参数,也可应用于泛型方法的类型参数。(注: CLR不允许基于类型参数名称或约束来进行重载; 只能基于类型参数个数对类型或方法进行重载)

          重写虚泛型方法时,重写的方法必须指定相同数量的类型参数,而且这些类型参数会继承在基类方法上指定的约束。事实上,根本不允许为重写方法的类型参数指定任何约束。但是类型参数的名称是可以改变的。 实现接口方法时类似。

 

主要约束

        类型参数可以指定零个或一个主要约束。主要约束可以是代表非密封类的一个引用类型。(不能指定以下特殊引用类型: System.Object, System.Array, System.Delegate, System.MulticastDelegate, System.ValueType, System,Enum 或者 System.Void)。

        指定引用类型约束时,相当于向编译器承诺: 一个指定的类型实参要么是与约束类型相同的类型,要么是从约束类型派生的类型。

 

次要约束

        类型参数可以指定零个或多个次要约束,次要约束代表接口类型。这种约束向编译器承诺类型实参实现了接口。

        还有一种次要约束称为类型参数约束,有时也称为裸类型约束。它允许一个泛型类型或方法规定: 指定的类型实参要么就是约束的类型,要么是约束的类型的派生类。如下:

        private static List<TBase> ConvertIList<T, TBase>(IList<T> list) where T: TBase
        {
            List<TBase> baseList = new List<TBase>(list.Count);
            for (int index = 0; index < list.Count; index++)
            {
                baseList.Add(list[index]);
            }
            return baseList;
        } 

 

构造器约束

        类型参数可指定零个或一个构造器约束, 它向编译器承诺类型实参是实现了公共无参构造器的非抽象类型。(注: 如果同时使用构造器约束和struct约束,C#编译器会认为这是一个错误,因为这是多余的。)

    internal class ConstructorConstraint<T> where T : new()
    {
        public static T Factory()
        {
            //允许,因为所有值类型都隐式有一个公共无参构造器。
            //如果指定的是引用类型,约束也要求它提供公共无参构造器
            return new T();
        }
    }

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值