zoukankan      html  css  js  c++  java
  • C#语法之泛型

    前面两篇C#语法主要是回顾委托相关的。这篇主要回顾了泛型。

    一、为什么要有泛型?

    我们在写一些方法时可能会方法名相同,参数类型不同的方法,这种叫做重载。如果只是因为参数类型不同里面做的业务逻辑都是相同的,那可能就是复制粘贴方法,改变参数类型,例如一些排序算法,int、float、double等类型的排序,参数数组存的数据类型不一样,还有像根据索引找到List集合中的对象。可能这个对象是Person、Dog等对象,这样方法改变的只是参数类型,那就是能不能写一个方法,传递不同的参数类型呢?于是乎有了泛型。

    二、什么是泛型?

    泛型通过参数化类型来实现在同一份代码上操作多种数据类型。例如使用泛型的类型参数T,定义一个类Stack<T>,可以用Stack<int>、Stack<string>或Stack<Person>实例化它,从而使类Stack可以处理int、string、Person类型数据。这样可以避免运行时类型转换或封箱操作的代价和风险,类似C++的模板。泛型提醒的是将具体的东西模糊化,这与后面的反射正好相反。

    三、泛型demo

    1.泛型类

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Generic
    {
        public class Stack<T>
        {
            private T[] s;
    
            int pos;
    
            public Stack(int size)
            {
                s = new T[size];
                pos = 0;
            }
    
            public void Push(T val)
            {
                s[pos] = val;
                pos++;
            }
    
            public T Pop()
            {
                pos--;
                return s[pos];
            }
    
            public void display()
            {
                Console.WriteLine("Stack Push:");
                foreach (T i in s)
                {
                    Console.WriteLine(i);
                }
            }
        }
    }
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Generic
    {
        class Program
        {
            static void Main(string[] args)
            {
                Stack<int> s1 = new Stack<int>(2);
                s1.Push(1);
                s1.Push(2);
                s1.display();
    
                Console.WriteLine("Stack Pop:");
                Console.WriteLine(s1.Pop());
                Console.WriteLine(s1.Pop());
    
                Stack<string> s2 = new Stack<string>(2);
                s2.Push(@"One");
                s2.Push(@"Two");
                s2.display();
    
                Console.WriteLine("Stack Pop:");
                Console.WriteLine(s2.Pop());
                Console.WriteLine(s2.Pop());
    
                Console.ReadLine();
    
    
            }
        }
    }

    上面定义了一个泛型类,主要是维护一个栈,栈里存放T类型的数据,在demo中可以定义int、string类型的栈,这样就很方便,使用一套代码可以维护多种数据类型。如果没有这个可能还要维护double、float等代码。

    2.泛型方法

    上面是泛型类,主要是在类层面进行参数化,我们还可以在更小的层面,在函数上进行泛型化。

    我们可以在上面Mina类中定义一个静态的泛型方法,用来获取找数值在数组中的位置。

            public static int Find<T>(T[] valus, T val)
            {
                for (int i = 0; i < valus.Length; i++)
                {
                    if (valus[i].Equals(val))
                    {
                        return i;
                    }
                }
                return -1;
            }

    我们可以用上面的方法来查找int数组、float数组

                int val = 4;
                int pos = Find<int>(new int[] {1,2,3,4,5 },val);
                Console.WriteLine(string.Format("int Pos:{0}",pos));
    
                float val1 = 4;
                pos = Find<float>(new float[] { 1, 2, 3, 4, 5 }, val1);
                Console.WriteLine(string.Format("float Pos:{0}", pos));
                Console.ReadLine();

    下面是两个demo的输出

    四、约束

    约束是指对泛型类型参数施加限制,用于限制可以传递到该类型参数的类型种类。如果使用某个约束不允许的类型来实例化,则会产生编译时错误。约束使用where关键字指定。

    约束有4种类型:

    1.基类约束

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

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

    { 类体}

    2.接口约束

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

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

    { 类体}

    3.默认构造函数约束

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

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

    { 类体}

    4.引用/值类型约束

    指示编译器泛型类型参数必须是引用类型或值类型

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

    { 类体}

    可以对同一类型参数使用多个约束,并且约束自身可以也可以是泛型类型,多个约束之间用逗号隔开。

    五、泛型委托

    泛型委托主要是想讲一下Action<T>和Func<TResult>两个委托,因为这两个在Linq中是经常见到的。

    Action<T>只能委托必须是无返回值的方法

    Fun<TResult>只是委托必须有返回值的方法

    不管是不是泛型委托,只要是委托委托那能用Lamdba表达式,因为不管Lamdba表达式还是匿名函数其实都是将函数变量化。

    下面简单的来做的demo说下两个的用法,这个会了基本linq会了一半了。

                Action<string> action = s => {
                    Console.WriteLine(s);
                };
                action("cuiyanwei");
               
    
                Func<int, int, int> func = (int a, int b)=>{
                    return a + b;
                };
                int result=func(1, 2);
                Console.WriteLine("sum:{0}",result);
    
                Console.ReadLine();

    上面其实都是将函数做为变量,这也是委托的思想。action是实例化了一个只有一个字符串参数没有返回值得函数变量。func是实例化了一个有两个int类型的参数返回值为int的函数变量。下面来看下输出结果:

    我们可以看到通过Lamdba表达式和泛型的结合,算是又方便了开发者们,更加方便实用。

    最后在这传统佳节情人节,祝各位单身狗(包括我)早日脱单,不过说实话今天我还是挺高兴的,朋友玩失踪又出现了,这算是节日最大的快乐吧。

  • 相关阅读:
    js正则匹配以某字符串开始字符串
    vue+vue-resource+vue-cookie随笔
    [考试反思]1001csp-s模拟测试(b):逃离
    [考试反思]0929csp-s模拟测试55:消逝
    [考试反思]0928csp-s模拟测试54:转瞬
    [考试反思]0927csp-s模拟测试53:沦陷
    [考试反思]0926csp-s模拟测试52:审判
    [考试反思]0924csp-s模拟测试51:破碎
    Function:凸包,决策单调性,题意转化,单峰函数三分,离线处理
    土兵占领:二分答案,最大流
  • 原文地址:https://www.cnblogs.com/5ishare/p/5754947.html
Copyright © 2011-2022 走看看