泛型类

83 阅读4分钟

泛型是什么

通过参数化类型来实现在同一份代码上操作多种数据类型。利用“参数化类型”将类型抽象化,从而实现灵活的复用。

泛型类

定义泛型方法就是定义一个方法,这个方法的参数的类型可以是不确定的,当调用这个方 法的时候再去确定方法的参数的类型。

情景是当需要把两个数据成员相加时候,数据成员类型固定的话,需要重复写代码,用泛型就可以根据参数的类型去判断使用什么类型

internal class Program
{
    static void Main(string[] args)
    {
        ClassA<int> a = new ClassA<int>(1, 2);

        Console.WriteLine(a.GetSum());

    }
}

class ClassA<T>
{
    private T a;
    private T b;

    public ClassA(T a, T b)
    {
        this.a = a;
        this.b = b;
    }
    public T GetSum()
    {
        dynamic num1 = a;
        dynamic num2 = b;
        dynamic result = num1 + num2;
        return (T)result;
    }
}

直接打印对象p,等价于打印p.ToString字符串,等价于打印该对象的路径

Program p = new Program();
Console.WriteLine(p.ToString());
Console.WriteLine(p);

所以可以重写该ToString方法,让它直接打印出对象的数据成员

internal class Student
{
    private int age;
    private string name;

    public Student(int age, string name)
    {
        this.age = age;
        this.name = name;
    }

    public override string ToString()
    {
        string result = age + ": " + name;
        return result;
    }

}
static void Main(string[] args)
{
    
    Student s = new Student(12,"小燕");
    Console.WriteLine(s);
}

这样就重写的ToString方法

泛型方法

同样是为了解决代码重复性,根据参数类型选择方法T类型

同一个类中,两个静态方法,可以不同类名.方法去调用,因为同一个类只能有一个GetSum函数,但是别的类的可以有GetSum函数,要调用别的类的GetSum静态函数,就要加类名

internal class Program
{
    static void Main(string[] args)
    {
       
        int result = GetSum<int>(45, 12);
        Console.WriteLine(result);


    }
    public static T GetSum<T>(T a, T b)
    {
        dynamic num1 = a;
        dynamic num2 = b;
        return (T)(num1 + num2);
    }
}

创建自己的MyList列表

引用类型的都要new,不构造不能直接调用任何成员

internal class MyList<T>
{
    private T[] data = new T[0];
    //所有的引用类型都要new,只声明或者赋值为null,空引用不能调用任何成员

    private int count = 0; //元素个数

    public int Capacity
    {
        get
        {
            return data.Length;
        }
        
    }
    //Count是private的,对外界提供属性,让外界可以访问到Count值,但不能修改Count值 
    public int Count
    {
        get
        {
            return count;
        }
    }
    public void Add(T item) 
    {
        if(data.Length == 0)
        {
            data = new T[4];
        }
        //把原来数组里的值赋值到新数组中,就是扩容
        if(data.Length == count)
        {
            T[] temp = new T[count*2];
            for(int i = 0; i < data.Length; i++)
            {
                temp[i] = data[i];
            }
            data = temp;
        }
        data[count] = item;
        count++;
    }
    //索引器实现
    public T this[int index]
    {
        get
        {
            if(index < 0 || index > count - 1)
            {
                throw new System.ArgumentOutOfRangeException("索引参数超出范围了");

            }
            return data[index];
        }
        set
        {
            data[index] = value;

        }
    }
    //插入实现
    public void Insert(int index, T item)
    {
        if(index < 0 || index > count -1)
        {
            throw new ArgumentOutOfRangeException("索引参数超出范围了");

        }
        for (int i = count - 1; i > index-1; i--)
        {
            //count-1到index
            data[i+1] = data[i];
        }
        data[index] = item;
        count++;
    }

    //删除实现
    public void RemoveAt(int index)
    {
        if(index < 0 || index > count - 1)
        {
            throw new ArgumentOutOfRangeException("索引参数超出范围了");

        }
        for(int i = index + 1; i < count; i++)
        {
            //从index+1到count-1
            data[i-1] = data[i];
        }
        count--;
    }
    //从前遍历查找某个值的位置
    public int IndexOf(T item)
    {
        int index = -1;

        for (int i = 0; i < count; i++)
        {
            //如果是用==比较的话,比较的是值类型,不能比较引用类型,因为比较的是引用地址
            if (item.Equals(data[i]))//使用Equals函数可以判断值类型和引用类型(只包括String等自带的),
                                     //如果T为Student类,比较两个对象,比较的是两个引用地址,要在Student类里重写Equals方法
            {
                index = i; break;
            }
        }
        return index;

    }
    //从后遍历查找某个值
    public int LastIndexOf(T item)
    {
        int index = -1;

        for (int i = count-1; i>=0; i--)
        {
            
            if (item.Equals(data[i]))
            {
                index = i; break;
            }
        }
        return index;
    }

    //排序
    public void Sort()
    {
        Array.Sort(data, 0, count);//排序数组data,从0开始,长度为count
    }



}

测试

static void Main(string[] args)
{
    MyList<int> list = new MyList<int>();
    Console.WriteLine(list.Capacity);

    list.Add(1);
    list.Add(2);
    list.Add(3);
    list.Add(4);
    list.Add(5);
    list.Add(2);
    list.Add(3);
    Console.WriteLine(list.Count);

    for(int i = 0; i < list.Count; i++)
    {
        Console.Write(list[i]+" ");
    }
    ////超出范围抛出异常
    //int temp1 = list[10];
    //int temp2 = list[-1];
    Console.WriteLine();
    list.RemoveAt(3);
    for(int i = 0;i < list.Count; i++)
    {
        Console.Write(list[i]+" ");
    }
    Console.WriteLine();

    Console.WriteLine(list.IndexOf(2));
    Console.WriteLine(list.LastIndexOf(2));

    //排序
    list.Sort();
    for (int i = 0; i < list.Count; i++)
    {
        Console.Write(list[i] + " ");
    }
}

Equals方法

Equals方法可以比较值类型,也可以比较一些引用类型,比如字符串,但是引用类型比较是比较地址,比如Student类,要比较两个Student类的对象,需要在Student类中,重写Equals方法,让Equals方法比较该类的数据成员,而不是引用比较

== 号比较的是值类型,比较引用类型也是比较地址,可以重载==号

Student类

internal class Student
{
    public int age;
    public string name;

    public Student(int age, string name)
    {
        this.age = age;
        this.name = name;
    }

    public override bool Equals(object obj)
    {
        //传入子类Student,用父类obj声明对象,类似于obj=new Student();
        //再把obj对象强制转换为原来Student类,因为不能父类不能赋给子类
        Student stu = (Student)obj;

        if(age == stu.age && name == stu.name)
        {
            return true;
        }
        return false;

    }
}

测试

static void Main(string[] args)
{
    int a = 1;
    int b = 1;

    Console.WriteLine(a.Equals(b));//等价于a==b

    String str1 = "hello";
    string str2 = "hello";
    Console.WriteLine(str1.Equals(str2));//内置已经重写Equals,可以实现比较字符串,但不能比较类

    Student stu1 = new Student(18, "小燕");
    Student stu2 = new Student(18, "小燕");

    Console.WriteLine(stu1.Equals(stu2));//在Student类中,已经重写了Equals方法用于比较数据成员

    Console.WriteLine(stu1 == stu2);//比较的是引用,也就是指向对象在堆的地址

}