金沙国际网址 > 摄影 > 泛型类的定义与一般类的定义几乎一样,泛型将

原标题:泛型类的定义与一般类的定义几乎一样,泛型将

浏览次数:186 时间:2019-11-09

配置参数

  • 特色:DVHZ 移动车 摄像轨道车 软硬轨道 脚轮三脚架通用携带方便 【大Y型B型】

查看完整参数>>

指示编译器泛型类型参数必须派生自特定接口。

6> 未绑定的类型参数

没有约束的类型参数(如公共类 SampleClass<T>{}中的 T)称为未绑定的类型参数。 未绑定的类型参数具有以下规则:

  • 不能使用 !=和 == 运算符,因为无法保证具体类型参数能支持这些运算符。

  • 可以在它们与 System.Object之间来回转换,或将它们显式转换为任何接口类型。

  • 可以将它们与 [null] 进行比较。 将未绑定的参数与 null进行比较时,如果类型参数为值类型,则该比较将始终返回 false。

 

2.泛型方法

1> 约束简介

在定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的类型种类施加限制。 如果客户端代码尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误。 这些限制称为约束。 约束是使用 where上下文关键字指定的。 下表列出了六种类型的约束:

约束 说明
T : struct 类型参数必须是值类型。
T : class 类型参数必须是引用类型;这一点也适用于任何类、接口、委托或数组类型。
T:new() 类型参数必须具有无参数的public构造函数。 当与其他约束一起使用时,new() 约束必须最后指定。
T:<基类名> 类型参数必须是指定的基类或派生自指定的基类。
T:<接口名称> 类型参数必须是指定的接口或实现指定的接口。 可以指定多个接口约束。 约束接口也可以是泛型的。
T:U 为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。

 

3.约束

4. 泛型接口:

语法:

     interface ITest1<K> 
    {

    }

一个接口可定义多个类型参数,如下所示:

     interface ITest1<K, V> 
    {

    }

适用于类的继承规则同样适用于接口:

     interface ITest1<S> 
    {

    }

    interface ITest2<K> : ITest1<K>
    {

    }

泛型接口的约束:

    interface ITest1<S> where S : class
    {

    }

泛型接口的约束继承

     interface ITest1<S> where S : class
    {

    }

    interface ITest2<K> : ITest1<K> where K : class
    {

    }

  2>    在尖括号中用逗号分隔的占位符字符串来表示希望提供的类型。这叫类型参数(Type Parameter)

约束是指对泛型类型参数施加限制,用于限制可以传递到该类型参数的类型种类。

8> 为泛型方法添加约束
        void SwapIfGreater<T>(ref T lhs, ref T rhs) where T : System.IComparable<T>
        {
            T temp;
            if (lhs.CompareTo(rhs) > 0)
            {
                temp = lhs;
                lhs = rhs;
                rhs = temp;
            }
        }

泛型方法可以使用许多类型参数进行重载。 例如,下列方法可以全部位于同一个类中:

        void DoWork() { }
        void DoWork<T>() { }
        void DoWork<T, U>() { }

   例如:

 

7> 作为约束的类型参数

将泛型类型参数作为约束使用,在具有自己类型参数的成员函数必须将该参数约束为包含类型的类型参数时非常有用,如下示例所示:

        class List<T>
        {
            void Add<U>(List<U> items) where U : T {/*...*/}
        }

在上面的示例中,T在 Add方法的上下文中是一个类型约束,而在 List 类的上下文中是一个未绑定的类型参数。

类型参数还可在泛型类定义中用作约束。 请注意,必须在尖括号中声明此类型参数与任何其他类型的参数:

SampleClass<T, U, V> where T : V { }

       扩展方法可以和泛型类结合使用,它允许我们将类中的静态方法关联到不同的泛型类上,还允许我们像调用类构造实例的实例方法一样来调用方法。

利用泛型也可以达到代码重用的目的。

2> 约束简介案例
    class TestClass<TestType> where TestType : struct
    {

    }

    static void Main(string[] args)
     {
            TestClass<int> t1 = new TestClass<int>();

            //TestClass<string> t2 = new TestClass<string>(); 错误,只能传递值类型
    }
       static class ExtendHolder

    {

        public static void Print<T>(this Holder<T> h) //声明扩展方法并关联到泛型类Holder<T>上。

        {

            T[] vals = h.GetValues(); //调用泛型类的方法。

            Console.WriteLine("{0},t{1},t{2}",vals[0],vals[1],vals[2]); //"t"转义符

        }

    }



    class Holder<T> //声明泛型类

    {

        T[] vals=new T[3];//声明并初始化数组。

        public Holder(T v0, T v1, T v2) //构造函数,为数组赋值。

        {

            vals[0] = v0;

            vals[1] = v1;

            vals[2] = v2;

        }

        public T[] GetValues() //声明方法,返回数组类型。

        {

            return vals;

        }

    }



    class Program

    {

        static voidMain(string[] args)

        {

            var intHolder = new Holder<int>(3,5,7); //创建泛型类实例

            var stringHolder = new Holder<string>("a1","b2","c3");



            intHolder.Print(); //调用方法

            stringHolder.Print();



            Console.ReadKey();

        }

    }

指示翻译器泛型类型参数必须为引用类型或值类型。

5> 约束多个参数

可以对多个参数应用约束,并对一个参数应用多个约束,如下面的示例所示

         class Base { }
         class Test<T, U>
            where U : struct
            where T : Base, new()
            { }

    图片 1

public void GetMax<T>(T t,int a)

3> 使用泛型约束的原因(优势)

如果要检查泛型列表中的某个项以确定它是否有效,或者将它与其他某个项进行比较,则编译器必须在一定程度上保证它需要调用的运算符或方法将受到客户端代码可能指定的任何类型参数的支持。 这种保证是通过对泛型类定义应用一个或多个约束获得的。 例如,基类约束告诉编译器:仅此类型的对象或从此类型派生的对象才可用作类型参数。 一旦编译器有了这个保证,它就能够允许在泛型类中调用该类型的方法。

可以对同一类型参数应用多个约束,并且约束自身可以是泛型类型,如下所示:

        class EmployeeList<T> where T : Employee, IEmployee, System.IComparable<T>, new()
        {
            // ...
        }

2, 泛型类?

d:引用/值类型约束

3. 约束:

      方法二:使用Var关键字隐式创建:

参数的类型可以是T或其他系统的数据类型。

4> 泛型约束的注意点:

通过约束类型参数,可以增加约束类型及其继承层次结构中的所有类型所支持的允许操作和方法调用的数量。 因此,在设计泛型类或方法时,如果要对泛型成员执行除简单赋值之外的任何操作或用 System.Object不支持的任何方法,您将需要对该类型参数应用约束。在应用 where T : class 约束时,避免对类型参数使用 == 和 != 运算符,因为这些运算符仅测试引用同一性而不测试值相等性。

       创建构造类型例如:

c.默认构造函数约束

2. 语法:

    class ClassName<Type>
    {
         public void Add(Type input)
        {
        }
    }

    class Program
    {
        public void test0()
        {
            ClassName<int> testClass = new ClassName<int>();
            testClass.Add(5);
            print<int>(5, 6);
            print(5, 6); // <>可以省略
        }

        public void print<T1>(T1 x, T1 y)
        {
            Console.WriteLine(x.ToString(),y.ToString());
        }

    }

       请仔细理解下面两张图,或许能更好地理解泛型的原理。

方法体

1. 简介:

2.0 版 C# 语言和公共语言运行时 (CLR) 中增加了泛型。 泛型将类型参数的概念引入 .NET Framework,类型参数使得设计如下类和方法成为可能:这些类和方法将一个或多个类型的指定推迟到客户端代码声明并实例化该类或方法的时候。

 

 

SomeClass<short, int> mySc1 = new SomeClass<short, int>(); //第一种方法创建泛型类实例。

}

       泛型方法和泛型委托相似,有两个参数列表:

泛型类的定义与一般类的定义几乎一样,只是它把一些参数用泛型的类型参数来代替。

       例如:

b.接口约束

       例如:

其中ab都是约束了父类或父接口,传递其子类或子接口也是能满足的。

  程序输出结果为:

指示编译器泛型类型参数公开了默认的公共构造函数(不带任何参数的公共构造函数)。即无参构造函数是public。

  2>    注意,在这里泛型委托有两个参数列表:委托形参列表和类型参数列表。

指示编译器泛型类型参数必须派生自特定基类。

  3>    在泛型类声明的主体中使用类型参数来表示应该被替代的类型。

格式:修饰符 class 类名<类型参数列表> where 类型参数:基类名

 

{

    图片 2

1.泛型类

  如下代码所示声明了一个SomeClass的泛型类:

}

 

{

       创建和使用常规的,非泛型的类的过程有两个步骤:声明类和创建类的实例。

泛型:即通过参数化类型来实现在同一份代码上操作多种数据类型。

    interface IMyIfc<T> //声明泛型接口,尖括号中为类型参数。

    {

        T ReturnIt(T inValue); //声明返回值类型为T的方法

    }



    class Simple<S> : IMyIfc<S> //声明泛型类,实现了泛型接口。

    {

        public S ReturnIt(S inValue) //实现接口成员方法。

        {

            return inValue;

        }

    }



    class Program

    {

        static voidMain(string[] args)

        {

            var trivInt = new Simple<int>(); //创建构造类型实例。尖括号中为类型实参。

            var trivString = new Simple<string>();



            Console.WriteLine("{0}",trivInt.ReturnIt(50)); //调用类对象实现的方法。

            Console.WriteLine("{0}",trivString.ReturnIt("Hi there!"));



            Console.ReadKey();

        }

    }

泛型方法与普通的方法区别在于使用类型参数声明方法,泛型方法也可以被重载和重写。

图片 3

修饰符 class 类名<类型参数列表>

图片 4

格式:修饰符 class 类名<类型参数列表> where 类型参数:接口名

 

格式:修饰符 class 类名<类型参数列表> where 类型参数:struct(或class)

       struct PieceOfData<T> //声明泛型结构

    {

        public PieceOfData(T value) //构造函数,初始化字段_Data。

        {

            _Data = value;

        }

        private T _Data;//声明私有字段(只能在类的内部访问)。

        public T Data //声明属性

        {

            get { return _Data; }

            set { _Data = value; }

        }

    }



    class Program

    {

        static voidMain()

        {

            var intData=new PieceOfData<int>(10);//创建构造类型实例

            var stringData=new PieceOfData<string>("Hi there!");



            Console.WriteLine("intData={0}",intData.Data);//访问属性

            Console.WriteLine("stringData={0}",stringData.Data);

            Console.ReadKey();

        }

    }

类体

1, 什么是泛型?

例如:

  1>    封闭在圆括号内的方法参数列表。

格式:

 

 

      例如:

a.基类约束

 

修饰符 class 类名<类型参数列表> where 类型参数 : new()

 

       在理解泛型的定义之前,我们要明白非泛型的概念,非泛型就是大部分情况下是声明一个类,然后封装需要的行为,最后创建这些类的实例。

 

       我们不能直接从泛型类型创建实例对象。首先,我们需要告诉编译器使用哪些真实类型来替代占位符(类型参数)。编译器获取这些真实类型并从它创建一个真实类型对象。

 

 

var mySc2 = new SomeClass<short, int>(); //第二种方法,使用Var关键字创建。

 

       泛型的类不是实际的类,而是类的模板,所以我们必须先从它们构建实际的类类型, 然后个构建后的类类型的实例。

 

  图片 5

       泛型是一种更准确地使用有一种以上的类型的代码的方式。泛型允许我们声明类型参数化的代码,我们可以用不同的类型进行实例化。总结为一句话就是,泛型类型是类型的模板。

       泛型接口的声明和非泛型接口的声明差不多,但是需要在接口名称之后的尖括号中有类型参数。

  图片 6

6, 泛型结构?

 

         class Program

    {

        static voidMain(string[] args)

        {

            var stackInt = new MyStack<int>(); //创建泛型类对象(或称实例),创建构造类型和创建实例可以一步完成。

            var stackString=new MyStack<String>();



            stackInt.Push(3); //调用方法

            stackInt.Push(5);

            stackInt.Push(7);

            stackInt.Print();



            stackString.Push("Generics are great!");

            stackString.Push("Hi there");

            stackString.Print();



            Console.ReadKey();

        }

    }

    class MyStack<T> //声明泛型类

    {

        T[] StackArray; //声明数组

        int StackPointer = 0; //声明并初始化整形变量。

        public void Push(T x) //定义无返回值方法

        {

            if (!IsStackFull)

            {

                StackArray[StackPointer++] = x; //为数组StackArray赋值。

            }

        }

        public T Pop() //定义有返回值方法

        {

            return (!IsStackEmpty) //条件运算符,可以用if...else...语句等价表示。

                ? StackArray[--StackPointer]

                : StackArray[0];

        }

        public MyStack() //构造函数初始化数组StackArray,为数组分配内存引用。

        {

            StackArray=new T[MaxStack];

        }

        public void Print() //构造函数

        {

            for (int i = StackPointer - 1; i >= 0; i--)

            {

                Console.WriteLine("Value:{0}",StackArray[i]);

            }

        }



        const int MaxStack = 10; //声明并初始化常量MaxStack

        bool IsStackFull //声明属性

        {

            get { return StackPointer >= MaxStack; }

        }

        bool IsStackEmpty //声明属性

        {

            get { return StackPointer <= 0; }

        }

    }

 

 

 

  1>    在类名之后放置一组尖括号。

5, 创建泛型类的变量和实例?

       方法一:和普通非泛型类的对象创建方法相似

       附:泛型栈和非泛型栈之间的区别总结如下图表:

       例如:

 

 

7, 泛型接口?

 

 

  例如:

 

 

非泛型

泛型

源代码大小

更大:我们需要为每种类型进行一个新的实现。

更小:不管构造类型的数量多少,我们只需要一个实现。

可执行大小

无论每一个版本的栈是否会被使用,都会在编译的版本中出现。

可执行文件中只会出现有构造类型的类型。

写的难易度

易于书写

比较难写

维护的难易度

更容易出问题,因为所有修改需要应用到每一个可用的类型上。

易于维护,因为只需要修改一个地方。

 

图片 7

class Simple //非泛型类

    {

        static public void ReverseAndPrint<T>(T[] arr) //声明泛型方法

        {

            Array.Reverse(arr);

            foreach (T item in arr) //遍历数组。使用类型参数T。

            {

                Console.Write("{0}",item.ToString());

                Console.Write("");

            }

            Console.WriteLine(); //换行

        }

    }



    class Program

    {

        static voidMain(string[] args)

        {

            //创建三种类型的数组。

            var intArray = new int[] { 3,5,7,9,11};

            var stringArray = new string[] { "first","second","third"};

            var doubleArray = new double[] { 3.567,7.891,2.345};



            Simple.ReverseAndPrint<int>(intArray); //调用泛型方法,显示调用

            Simple.ReverseAndPrint(intArray); //使用推断类型隐式调用。



            Simple.ReverseAndPrint<string>(stringArray);

            Simple.ReverseAndPrint(stringArray);



            Simple.ReverseAndPrint<double>(doubleArray);

            Simple.ReverseAndPrint(doubleArray);



            Console.ReadKey();



        }

    }

      程序输出结果为:

4, 创建构造类型?

 

SomeClass<short,int> //尖括号中为类型实参

  2>    封闭在尖括号内的类型参数列表。

 class SomeClass<T1, T2> //声明泛型类SomeClass,尖括号中是类型参数。

     {

        public T1 SomeVar = new T1(); //通常在这些位置使用类型。

     }

     程序输出结果如下:

10,扩展方法和泛型类?

      关于泛型先写到这里,欢迎大家指正,谢谢!

 

图片 8

       声明一个泛型类和声明普通类差不多,主要有如下区别:

     程序输出结果为:

3, 声明泛型类?

 

     程序输出结果为:

8, 泛型委托?

 

       创建泛型类实例一般有两种方法:

9, 泛型方法?

 

 

       下图演示了泛型类的创建过程:

    图片 9

      程序输出结果为:

  1>    要声明泛型委托,在委托名称之后,委托参数列表之前的尖括号中放类型参数列表。

      

     注:泛型和非泛型区分的最主要的标志是:泛型类有尖括号。

   图片 10

delegate void MyDelegate<T>(T value); //声明泛型委托



    class Simple

    {

        public static void PrintString(string s) //方法匹配委托,

        {

            Console.WriteLine(s);

        }



        public static void PrintUpperString(string s)

        {

            Console.WriteLine("{0}", s.ToUpper());//调用string的ToUpper方法实现将字符串转换为大写。

        }

    }



    class Program

    {

        static voidMain(string[] args)

        {

            var MyDel = new MyDelegate<string>(Simple.PrintString); //创建委托的实例

            MyDel += Simple.PrintUpperString; //为委托添加方法。

            if (null != MyDel) //判断委托是否为空。

            {

                MyDel("VinceInfo");//调用委托。

            }

            else

            {

                Console.WriteLine("Delegate is empty!");

            }

            Console.ReadKey();

        }

    }

 

本文由金沙国际网址发布于摄影,转载请注明出处:泛型类的定义与一般类的定义几乎一样,泛型将

关键词:

上一篇:富莱仕 C900S影视灯LED摄像灯 单灯 单灯

下一篇:在运行时知道一个函数有什么参数,函数参数