前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >认真CS☀️泛型

认真CS☀️泛型

作者头像
星河造梦坊官方
发布2024-08-14 16:45:46
1100
发布2024-08-14 16:45:46
举报
文章被收录于专栏:星河造梦坊专栏

🟥 非泛型

为什么要用泛型?那么先来看下面两个功能相似的非泛型类

这个类都是int

代码语言:javascript
复制
class MyIntStack
{
    int[] StackArry;

    public void Push(int x)
    {
    }
}

这个类都是float

代码语言:javascript
复制
class MyFloatStack
{
    float[] StackArry;

    public void Push(float x)
    {
    }
}

第一个类实现了int型的功能,第二个类通过剪切、改类名、将int改为float实现float型功能,通过这种方式的变换实现float型功能当然可行,但有以下缺点:

a、需检查类声明哪些需更改,哪些需保留

b、每次添加新类型(long、double...)等时都要重写代码

c、有很多相同代码副本,占用空间

d、调试和维护复杂且易出错

泛型提供了这些问题的更好的解决方式

🟧 泛型

泛型可让多个类型共享一组代码,泛型允许我们声明类型参数化的代码,可以用不同的类型进行实例化。也就是说,我们可以用“类型占位符”来写代码,然后在创建类的实例时指明真实的类型

C#提供了5种泛型:类、结构、接口、委托和方法

示例:

代码语言:javascript
复制
class Stack<T>
{
    T[] StackArry;

    public void Push(T x)
    {
    }
}

1️⃣ 泛型类

🚩 声明泛型类

注意:

a、在类名之后放置一组尖括号

b、在尖括号中用逗号分隔的占位符字符串来表示希望提供的类型,占位字符串叫做类型参数

c、在泛型类声明的主体中使用类型参数来表示应该替换的类型

代码语言:javascript
复制
class SomeClass<T1, T2>
{
    public T1 SomeVar = new T1();
    public T2 SomeVar = new T2();
}
🚩 创建构造类型

作用:告诉编译器能使用哪些真是类型来替代占位符(类型参数),编译器获取这些真实类型来创建构造类型(即创建真实类对象的模板)。要替代类型参数的真是类型叫做类型实参

代码语言:javascript
复制
SomeClass<short,int>
🚩 创建变量和实例

创建了类的模板后,我们还要将他实例化才可使用,实例化也就意味着赋给变量,所以要创建变量

代码语言:javascript
复制
SomeClass<short, int> mySc1 = new SomeClass<short, int>();
var mySc2 = new SomeClass<short, int>(); 

注意实例化的<>()

🚩 使用泛型的栈的示例
代码语言:javascript
复制
using System;

class MyStack<T>
{
    T[] StackArray;
    int StackPointer = 0;

    public void Push(T x)
    {
        if (!IsStackFull)
            StackArray[StackPointer++] = x;
    }

    public T Pop()
    {
        return (!IsStackEmpty)
            ? StackArray[--StackPointer]
            : StackArray[0];
    }

    const int MaxStack = 10;
    bool IsStackFull
    {
        get
        {
            return StackPointer >= MaxStack;
        }
    }
    bool IsStackEmpty
    {
        get
        {
            return StackPointer <= 0;
        }
    }

    public MyStack()
    {
        StackArray = new T[MaxStack];
    }

    public void Print()
    {
        for (int i = StackPointer - 1; i >= 0; i--)
            Console.WriteLine("Value:{0}", StackArray[i]);
    }
}

class Program
{
    static void Main()
    {
        MyStack<int> StackInt = new MyStack<int>();
        var StackString = new MyStack<String>();

        StackInt.Push(3);
        StackInt.Push(5);
        StackInt.Push(7);
        StackInt.Push(9);
        StackInt.Print();

        StackString.Push("This is fun!");
        StackString.Push("Hi there!");
        StackString.Print();
    }
} 

知识回顾:

条件运算符属性

2️⃣ 类型参数的约束where子句

where约束T必须继承自某一接口,方便我们调用T里面的方法。

代码语言:javascript
复制
    // IRole的作用是约束传入的两个参数类型必须要实现IRole这个接口;
    public bool CompareLevel<T, K>(T t1, K t2) where T : IRole where K : IRole
    {
        return t1.level >= t2.level;
    }

    //那么怎么使用泛型呢?
    public void Test()
    {
        //先定义三个测试用的类型
        MyNPC npc = new MyNPC();
        MyPlayer player = new MyPlayer();
        MyMonster monster = new MyMonster();

        //对各个类型的level赋值
        npc.level = 1;
        player.level = 2;
        monster.level = 3;

        //比较npc和player的level就很简单了,只需要这样调用即可
        bool b1 = CompareLevel(npc, player);
        bool b2 = CompareLevel<MyNPC, MyMonster>(npc, monster);
    }

    public interface IRole
    {
        int level { get; set; }
    }

    public class MyPlayer : IRole
    {
        public int level { get; set; }
    }

    public class MyNPC : IRole
    {
        public int level { get; set; }
    }

    public class MyMonster : IRole
    {
        public int level { get; set; }
    }
🚩 泛型方法

3️⃣ 扩展方法

扩展方法回顾

和非泛型类一样,泛型类的扩展方法:

a、必须声明为static

静态类不必生成新的实例,Main方法可直接调用另一个类(静态类为此类扩展类,间接调用扩展类)

静态类内为静态成员

b、第一个参数类型中必须有关键字this,后面是扩展的泛型类的名字

代码语言:javascript
复制
using System;

class A<T>
{
    T[] vals = new T[3];
    public A(T T1, T T2, T T3)
    {
        vals[0] = T1;
        vals[1] = T2;
        vals[2] = T3;
    }

    public void GetValues()
    {
        Console.WriteLine("{0},{1},{2}",vals[0], vals[1], vals[2]);
    }
}

static class B
{
    static public void Test<T>(this A<T> h)
    {
        h.GetValues(); 
    }
}

class Program
{
    static void Main()
    {
        var a = new A<int>(5, 6, 7);
        a.Test();
    }
    
}

4️⃣ 泛型结构

与泛型类相似,泛型结构可以有类型参数和约束。泛型结构的规则和条件与泛型类是一致的

代码语言:javascript
复制
using System;

struct P<T>
    where T : struct
{
    private T a;
    public T b
    {
        get { return a; }
        set { a = value; }
    }
}

class Program
{
    static void Main()
    {
        var p = new P<int>();
        p.b = 10;
        Console.WriteLine(p.b);
    }
}

5️⃣ 泛型委托

委托知识回顾

代码语言:javascript
复制
using System;

public delegate string Func<T1, T2, T3>(T1 p1, T2 p2);

class Simple
{
    static public string PrintString(int p1,int p2)
    {
        int total = p1 + p2;
        return total.ToString();
    }
}

class Program
{
    static void Main()
    {
        //var myDel = new Func<int, int, string>(Simple.PrintString);
        //Console.WriteLine("Total:{0}", myDel(15, 13));

        Console.WriteLine("Total:{0}", new Func<int, int, string>(Simple.PrintString)(15, 13));
        //传入的方法数值应该传入的方法之后!
    }
}

本例中委托形参负责将数据传入委托中的方法。委托返回类型为string,是因为委托中的方法返回类型为string,当然委托类型为object也是可以的

6️⃣ 泛型接口

泛型接口允许我们编写参数和接口成员返回类型都是泛型类型参数的接口。泛型接口的声明和非泛型接口的声明差不多

🚩 在Main中实现将占位符替换为实际类型参数
代码语言:javascript
复制
using System;

interface Iif<T>
{
    T ReturnIt(T invalue);
}

class Simple<T> : Iif<T>
{
   public T ReturnIt(T invalue)
    {
        return invalue;
    }
}

class Program
{
    static void Main()
    {
        var a = new Simple<int>();
        var b = new Simple<string>();

        Console.WriteLine(a.ReturnIt(10));
        Console.WriteLine(b.ReturnIt("good"));

    }
}
🚩 在接口实现中将占位符替换为实际类型参数

这样可继承多个不同实际类型参数,若是只写继承一个接口而希望实现两个接口,那是系统所不允许的,因为那可能出现两个相同类型参数,造成冲突

代码语言:javascript
复制
using System;

interface Iif<T>
{
    T ReturnIt(T invalue);
}

class Simple: Iif<int>,Iif<string>
{
   public int ReturnIt(int invaluea)
    {
        return invaluea;
    }

    public string ReturnIt(string invalueb)
    {
        return invalueb;
    }
}

class Program
{
    static void Main()
    {
        var a = new Simple();

        Console.WriteLine(a.ReturnIt(10));
        Console.WriteLine(a.ReturnIt("good"));

    }
}
🚩 泛型接口的实现必需唯一
代码语言:javascript
复制
class Simple : Iif<int>, Iif<S>   //报错,因为S可能为int型,类会产生两个重复的接口,这是不允许的
{
   public int ReturnIt(int invalue)
    {
        return invalue;
    }

    public S ReturnIt(S invalue)
    {
        return invalue;
    }
}

泛型接口名字不会和非泛型冲突(若都是泛型或非泛型,出现相同的接口名,则会冲突),我们还可声明一个跟泛型名字一样的非泛型接口,如下代码所示

代码语言:javascript
复制
interface Iif<T>
{
    T ReturnIt(T invalue);
}

interface Iif
{
    int ReturnIt(int invalue);
}

大家还有什么问题,欢迎在下方留言!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-09-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 🟥 非泛型
  • 🟧 泛型
    • 1️⃣ 泛型类
      • 🚩 声明泛型类
      • 🚩 创建构造类型
      • 🚩 创建变量和实例
      • 🚩 使用泛型的栈的示例
    • 2️⃣ 类型参数的约束where子句
      • 🚩 泛型方法
    • 3️⃣ 扩展方法
      • 4️⃣ 泛型结构
        • 5️⃣ 泛型委托
          • 6️⃣ 泛型接口
            • 🚩 在Main中实现将占位符替换为实际类型参数
            • 🚩 在接口实现中将占位符替换为实际类型参数
            • 🚩 泛型接口的实现必需唯一
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档