6.泛型

6.泛型-泛型


6.1 知识点

泛型是什么

泛型实现了类型参数化,达到代码重用的目的。通过类型参数化来实现同一份代码操作多种类型。

泛型相当于类型占位符,定义类或方法时使用替代符代表变量类型,当真正使用类或方法时再具体指定类型。

泛型分类

  1. 泛型类

    • 基本语法:class 类名<泛型占位字母>
  2. 泛型接口

    • 基本语法:interface 接口名<泛型占位字母>
  3. 泛型方法

    • 基本语法:方法名<泛型占位字母>(参数列表)
    • 注意:泛型占位字母可以有多个,用逗号分开。

泛型类和泛型接口

在类和接口的语句块外部(namespace语句块内)

  • 泛型类

    • 单个泛型占位符的泛型测试类:

      class SingleGenericClass<T>
      {
          public T value;
      }
      
    • 多个泛型占位符的泛型测试类:

      class MultiGenericClass<T1, T2, K, M, LL, Key, Value>
      {
          public T1 value1;
          public T2 value2;
          public K value3;
          public M value4;
          public LL value5;
          public Key value6;
          public Value value7;
      }
      
  • 泛型接口

    interface IGenericInterface<T>
    {
        T Value { get; set; }
    }
    

在主函数内

  • 实例化泛型类:

    SingleGenericClass<int> t = new SingleGenericClass<int>();
    t.value = 10;
    Console.WriteLine(t.value); // 输出:10
    
    SingleGenericClass<string> t2 = new SingleGenericClass<string>();
    t2.value = "123123";
    Console.WriteLine(t2.value); // 输出:123123
    
    MultiGenericClass<int, string, float, double, SingleGenericClass<int>, uint, short> t3 = 
        new MultiGenericClass<int, string, float, double, SingleGenericClass<int>, uint, short>();
    

泛型方法

在类和接口的语句块外部(namespace语句块内)

  • 普通类中的泛型方法

    class GenericTest2
    {
        public void GenericFunction<T>(T value)
        {
            Console.WriteLine(value);
        }
    
        public void GenericFunction<T>()
        {
            T t = default(T);
        }
    
        public T GenericFunction<T>(string v)
        {
            return default(T);
        }
    
        public void GenericFunction<T, K, M>(T t, K k, M m)
        {
    
        }
    }
    
  • 泛型类中的泛型方法

    class GenericTest2<T>
    {
        public T value;
    
        public void TestFun<K>(K k)
        {
    
        }
    
        public void TestFun(T t)
        {
    
        }
    }
    

在主函数内

  • 普通类中的泛型方法

    GenericTest2 genericTest2 = new GenericTest2();
    genericTest2.GenericFunction<string>("123123"); // 输出:123123
    
  • 泛型类中的泛型方法

    GenericTest2<int> genericTest_2 = new GenericTest2<int>();
    genericTest_2.TestFun(10); // 这不是泛型方法,相当于调用TestFun(int t)
    genericTest_2.TestFun<string>("123"); // 输出:123
    genericTest_2.TestFun<float>(1.2f); // 输出:1.2
    genericTest_2.TestFun(true);
    genericTest_2.TestFun<int>(250); // 这才是泛型方法
    genericTest_2.TestFun(250); // 这样用的还是泛型方法
    

泛型的作用

  • 不同类型对象的相同逻辑处理可以选择泛型。
  • 使用泛型可以一定程度避免装箱拆箱。

举例:优化 ArrayList。传入泛型后,不同类型数组可以复用相同的代码。

class ArrayList<T>
{
    private T[] array;

    public void Add(T value)
    {

    }

    public void Remove(T value)
    {

    }
}

总结

  • 申明泛型时,它只是一个类型的占位符。
  • 泛型真正起作用的时候是在使用它的时候。
  • 泛型占位字母可以有 n 个,用逗号分开。
  • 泛型占位字母一般是大写字母。
  • 不确定泛型类型时,获取默认值可以使用 default(占位字符)
  • 看到 < > 包裹的字母,那肯定是泛型。

6.2 知识点代码

using System;

namespace Lesson5_泛型
{
    #region 知识点一 泛型是什么
    //泛型实现了类型参数化,达到代码重用目的
    //通过类型参数化来实现同一份代码上操作多种类型

    //泛型相当于类型占位符
    //定义类或方法时使用替代符代表变量类型
    //当真正使用类或者方法时再具体指定类型
    #endregion

    #region 知识点二 泛型分类

    //泛型类
    //基本语法:class 类名<泛型占位字母>

    //泛型接口
    //基本语法:interface 接口名<泛型占位字母>

    //泛型方法
    //基本语法:方法名<泛型占位字母>(参数列表)

    //注意:泛型占位字母可以有多个,用逗号分开

    #endregion

    //class语句块外 namespace语句块内

    #region 知识点三 泛型类和泛型接口

    //一个泛型占位符的泛型测试类
    class SingleGenericClass<T>
    {
        public T value;
    }

    //多个泛型占位符的泛型测试类
    class MultiGenericClass<T1, T2, K, M, LL, Key, Value>
    {
        public T1 value1;
        public T2 value2;
        public K value3;
        public M value4;
        public LL value5;
        public Key value6;
        public Value value7;
    }

    //泛型接口
    interface IGenericInterface<T>
    {
        T Value
        {
            get;
            set;
        }
    }

    //继承泛型接口的类 继承的时候要传入实际的类型
    class GenericTest : IGenericInterface<int>
    {
        //里面的变量会变成传入的实际类型
        public int Value { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
    }

    #endregion

    #region 知识点四 泛型方法

    //1.普通类中的泛型方法
    class GenericTest2
    {
        //使用的时候传入实际的类型
        public void GenericFunction<T>(T value)
        {
            Console.WriteLine(value);
        }

        //泛型方法可以重载
        public void GenericFunction<T>()
        {
            //用泛型类型 在里面做一些逻辑处理

            //因为没传入之前不知道泛型是什么类型 想设置默认值会报错
            //T t = 0;//报错
            //T t = null;//报错

            //使用 default(类型) 可以得到类型的默认值
            T t = default(T);
        }

        //泛型可以作为返回值
        public T GenericFunction<T>(string v)
        {
            return default(T);
        }

        //多个泛型占位符的泛型方法
        public void GenericFunction<T, K, M>(T t, K k, M m)
        {

        }
    }

    //2.泛型类中的泛型方法
    //虽然类名也叫GenericTest2 但是和上面的普通类GenericTest2已经不是一个类了
    //泛型也可以说是类名的一部分
    class GenericTest2<T>
    {
        public T value;

        //这才是泛型方法 实际使用时要传入类型
        public void TestFun<K>(K k)
        //public void TestFun<T>(T t)//不能叫T了 因为外面的泛型类的泛型占位符也是T 再叫T会分不清楚是谁的
        {
            Console.WriteLine(k);
        }

        //这个不叫泛型方法 因为 T是泛型类申明的时候 就指定 在使用这个函数的时候 
        //我们不能再去动态的变化了
        public void TestFun(T t)
        {

        }
    }

    #endregion

    #region 知识点五 泛型的作用
    //1.不同类型对象的相同逻辑处理就可以选择泛型
    //2.使用泛型可以一定程度避免装箱拆箱
    //举例:优化ArrayList
    //传入泛型后 不同类型数组的可以复用代码
    class ArrayList<T>
    {
        private T[] array;

        public void Add(T value)
        {

        }

        public void Remove(T value)
        {

        }
    }
    #endregion

    #region 总结
    //1.申明泛型时 它只是一个类型的占位符
    //2.泛型真正起作用的时候 是在使用它的时候
    //3.泛型占位字母可以有n个用逗号分开
    //4.泛型占位字母一般是大写字母
    //5.不确定泛型类型时 获取默认值 可以使用default(占位字符)
    //6.看到<>包裹的字母 那肯定是泛型
    #endregion

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("泛型");

            //主函数内

            #region 知识点三 泛型类和泛型接口

            //一个泛型占位符的泛型测试类

            //泛型占位符T中传入int类型 对应类里的T类型变量value学组就是int类型
            SingleGenericClass<int> t = new SingleGenericClass<int>();
            t.value = 10;
            Console.WriteLine(t.value);//10

            //泛型占位符T中传入string类型 对应类里的T类型变量value学组就是string类型
            SingleGenericClass<string> t2 = new SingleGenericClass<string>();
            t2.value = "123123";
            Console.WriteLine(t2.value);//123123

            //多个泛型占位符的泛型测试类
            //泛型类的占位符也可以填泛型类
            MultiGenericClass<int, string, float, double, SingleGenericClass<int>, uint, short> t3 =
                new MultiGenericClass<int, string, float, double, SingleGenericClass<int>, uint, short>();

            #endregion


            #region 知识点四 泛型方法

            //普通类中的泛型方法
            //new出普通类
            GenericTest2 genericTest2 = new GenericTest2();
            //调用类的泛型方法时传入类型
            genericTest2.GenericFunction<string>("123123");//123123

            //泛型类中的泛型方法
            //new出泛型类
            GenericTest2<int> genericTest_2 = new GenericTest2<int>();
            //这个不叫泛型方法 因为 T是泛型类申明的时候 就指定 在使用这个函数的时候 
            //我们不能再去动态的变化了
            genericTest_2.TestFun(10);
            //这才是泛型方法 实际使用时要传入类型
            genericTest_2.TestFun<string>("123");//123
            genericTest_2.TestFun<float>(1.2f);//1.2f
            genericTest_2.TestFun(true);
            //假如没有同名的方法 甚至可以省略传入类型 会根据传入的参数类型自动传入实际类型
            //建议还是要传类型 更清晰
            genericTest_2.TestFun<int>(250);//这样用的还是泛型方法
            genericTest_2.TestFun(250);
            //这样就不是泛型方法了 因为genericTest_2是泛型int类 里面有TestFun(T t)这个方法
            //传入int相当于有TestFun(int t)这个方法 会调用到这个方法里 所以想要调用泛型方法不能省略<int>了

            #endregion
        }
    }
}

6.3 练习题

定义一个泛型方法,判断类型并返回类型名称与占有的字节数

class语句块内,主函数外

// 判断类型泛型方法
static string JudgeTypeFunction<T>()
{
    if (typeof(T) == typeof(int))
    {
        return string.Format("{0},{1}字节", "整形", sizeof(int));
    }
    else if (typeof(T) == typeof(char))
    {
        return string.Format("{0},{1}字节", "字符", sizeof(char));
    }
    else if (typeof(T) == typeof(float))
    {
        return string.Format("{0},{1}字节", "单精度浮点数", sizeof(float));
    }
    else if (typeof(T) == typeof(string))
    {
        return string.Format("{0},{1}字节", "字符串", "不定");
    }
    return "其它类型";
}

主函数内

Console.WriteLine(JudgeTypeFunction<int>());    // 整形,4字节
Console.WriteLine(JudgeTypeFunction<string>()); // 字符串,?字节
Console.WriteLine(JudgeTypeFunction<char>());   // 字符,2字节
Console.WriteLine(JudgeTypeFunction<float>());  // 单精度浮点数,4字节
Console.WriteLine(JudgeTypeFunction<double>()); // 其它类型
Console.WriteLine(JudgeTypeFunction<uint>());   // 其它类型

6.4 练习题代码

using System;

namespace Lesson5_练习题
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("泛型练习题");

            //主函数内

            #region 练习题一
            //定义一个泛型方法,方法内判断该类型为何类型,并返回类型的名称与占有的字节数
            //如果是int,则返回“整形,4字节”
            //只考虑以下类型
            //int:整形
            //char:字符
            //float:单精度浮点数
            //string:字符串
            //如果是其它类型,则返回“其它类型”
            //(可以通过typeof(类型) == typeof(类型)的方式进行类型判断)

            Console.WriteLine(JudgeTypeFunction<int>());//整形,4字节
            Console.WriteLine(JudgeTypeFunction<string>());//字符串,?字节
            Console.WriteLine(JudgeTypeFunction<char>());//字符,2字节
            Console.WriteLine(JudgeTypeFunction<float>());//单精度浮点数,4字节
            Console.WriteLine(JudgeTypeFunction<double>());//其它类型
            Console.WriteLine(JudgeTypeFunction<uint>());//其它类型

            #endregion
        }

        //class语句块内 主函数外

        #region 练习题一

        //判断类型泛型方法
        static string JudgeTypeFunction<T>()
        {
            if (typeof(T) == typeof(int))
            {
                return string.Format("{0},{1}字节", "整形", sizeof(int));
            }
            else if (typeof(T) == typeof(char))
            {
                return string.Format("{0},{1}字节", "字符", sizeof(char));
            }
            else if (typeof(T) == typeof(float))
            {
                return string.Format("{0},{1}字节", "单精度浮点数", sizeof(float));
            }
            else if (typeof(T) == typeof(string))
            {
                return string.Format("{0},{1}字节", "字符串", "?");
            }
            return "其它类型";
        }
        #endregion
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏