c#——泛型

泛型——

泛型定义:定义时使用类型占位符T,泛型就延伸出——泛型类,泛型方法,泛型委托,泛型接口。因此在定义以上类型时,就在方法、类、委托、接口 名称后<T> T:占位符 。

泛型思想:实际类型的指定,是推迟到调用时去指定实际类型——推迟一切可推迟的。

为了更好的理解什么时候使用泛型,我们观察下列方法——

        /// <summary>
        /// 将字符串转换成整型
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public int ToInt(string str)
        {
            int re = 0;
            int.TryParse(str, out re);
            return re;
        }

        /// <summary>
        /// 将字符串转换为float
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public float ToFloat(string str)
        {
            float re = 0;
            float.TryParse(str, out re);
            return re;
        }

        /// <summary>
        /// 将字符串转换为decimal
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public decimal ToDecimal(string str)
        {
            decimal re = 0;
            decimal.TryParse(str, out re);
            return re;
        }

        /// <summary>
        /// 将字符串转换为double
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public double ToDouble(string str)
        {
            double re = 0;
            double.TryParse(str, out re);
            return re;
        }

从以上方法可以看出,我们对字符串进行转换时的方法逻辑是一样的,只是返回的数据类型不同。那为了减少代码的书写,我们就可以将以上方法写成一个方法。——

public T ToType<T>(string str){
    
    return Convert.ChangeType(str,typeof(T));
}

然后当我们想调用时——

  int val1= model.ToType<int>("123");//这里自动推算,调用时必须显式加上<int>
  float  val2= model.ToType<float>("34.6");

因此得出一句话,泛型方法的使用场景——方法具有相似的逻辑,但是传入的参数类型或返回的类型不同。调用时,传入具体类型和参数。


泛型类

我们定义一个类

public   class UserInfo
    {
        public int Id
        {
            get;
            set;
        }

        public int UserAge
        {
            get; set;
        }

        public string Name
        {
            get; set;
        }
    }

同样的,泛型类也是相似的逻辑——我们定义一个泛型类——(类似于List<T>)

public class MyList<T> {

List<T> lst=new List<T>();

public int size{

get{

return lst.Count;

}
}

public void Add<T>(T t){

lst.Add(t);
}

public void Remove<T>(T t){

lst.Remove(t);

}

}

在应用泛型类时

                 //应用泛型类
                MyList<UserInfo> userList = new MyList<UserInfo>();
                userList.Add(new UserInfo() { Id = 1, Name = "Jsey" });
                userList.Add(new UserInfo() { Id = 2, Name = "Whitle" });

以上就将UserInfo这个类型以 Id = 1, Name = "Jsey"添加到userList中,我们可以这样调用UserInfo user=userList[1]。也可以直接使用userList[1]。


泛型接口

泛型接口的定义与调用——

 //泛型接口
    public  interface IBaseModel<T>
    {
        void Add(T t);
        void Delete(T t);

        T GetModel(int id);
    }

接口类的具体实现——

 //泛型接口的实现类:泛型类
    class BaseModelNew<T> : IBaseModel<T>
    {
        public void Add(T t)
        {
            Console.WriteLine($"Add  {t.GetType().Name}");
        }

        public void Delete(T t)
        {
            Console.WriteLine($"Delete  {t.GetType().Name}");
        }

        public T GetModel(int id)
        {
            Console.WriteLine($"GetModel  {typeof(T).Name}");
            return default(T);
        }
    }

在主函数中的调用——先定义一个类型UserInfo user=userList[1];

          {      IBaseModel<UserInfo> iUser = new BaseModelNew<UserInfo>();
                iUser.Add(user);
                iUser.Delete(user);
                iUser.GetModel(1);
}

泛型委托详见Func和Action


简单了解——泛型的约束——

1)值类型约束——T:struct

     //1)T:struct 值类型约束  2)引用类型约束 T:class   ,1)和2)不能同时用
    // 3)无参构造函数约束 new() 若与其他约束一起使用,只能在最后
    //4)基类约束  
    //5) 接口约束   应用实际类型必须实现该接口 T:IBase
    public class MyList<T> where T:struct
    {
        List<T> childs = new List<T>();

        public int Size
        {
            get
            {
                return childs.Count;
            }
        }

        public void Add(T t)
        {
            childs.Add(t);
        }

        public void Remove(T t)
        {
            childs.Remove(t);
        }
}

有了T:struct后,我们在定义和使用这个类时就有了相对应的约束即——定义这个类时的<>中的内容必须是值类型才行。

 // 值类型
                MyList<int> myIds = new MyList<int>();
                myIds.Add(12);
                myIds.Add(34);
                myIds.Remove(12);
                //myIds.Add(23.5);
                MyList<double> myIds1 = new MyList<double>();

2)引用类型约束——T:class

如果我们将struct改成class,则在定义和使用时,<>中的类型必须时引用类型。

 //1)T:struct 值类型约束  2)引用类型约束 T:class   ,1)和2)不能同时用
    // 3)无参构造函数约束 new() 若与其他约束一起使用,只能在最后
    //4)基类约束  
    //5) 接口约束   应用实际类型必须实现该接口 T:IBase
    public class MyList<T> where T:class
    {
        List<T> childs = new List<T>();

        public int Size
        {
            get
            {
                return childs.Count;
            }
        }

        public void Add(T t)
        {
            
            childs.Add(t);
        }

        public void Remove(T t)
        {
            childs.Remove(t);
        }
}
//引用类型
                MyList<StudentInfo> myStuList = new MyList<StudentInfo>();//引用类型约束时,正确的
                MyList<UserInfo> userList = new MyList<UserInfo>();

3)无参构造函数约束——new()

 //1)T:struct 值类型约束  2)引用类型约束 T:class   ,1)和2)不能同时用
    // 3)无参构造函数约束 new() 若与其他约束一起使用,只能在最后
    //4)基类约束  
    //5) 接口约束   应用实际类型必须实现该接口 T:IBase
    public class MyList<T> where T:class,new()
    {
        List<T> childs = new List<T>();

        public int Size
        {
            get
            {
                return childs.Count;
            }
        }

        public void Add(T t)
        {
            T t1 = new T();//可以创建一个类型的实例(有了无参构造函数约束才行)
            childs.Add(t);
        }

        public void Remove(T t)
        {
            childs.Remove(t);
        }
}

有了以上的无参构造函数的约束,我们就不能够在使用这个函数的时候使用

 //引用类型
                MyList<StudentInfo> myStuList = new MyList<StudentInfo>();//引用类型约束时,正确的
                MyList<UserInfo> userList = new MyList<UserInfo>();
                 MyList<string> strList = new MyList<string>(); // 它对new() 无效

使用上面最后一句的时候,会报错——

 有了无参构造函数的约束,可以在当前类下创建实例。

4)基类约束

创建一个公有类——

 public class ModelBase
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

在一个基础类中创建一个方法——

 //基类约束  不能既是引用约束又是基类约束
        public void ShowInfo<T>(T t) where T: ModelBase,IBase
        {
            Console.WriteLine($"Id:{t.Id} Name:{t.Name}");
        }

将UserInfo修改成——

   public class UserInfo : ModelBase
    {
        
    }

在调用时,我们就会有约束了——<>中的类型需要时ModelBase派生出来的

BaseModel model = new BaseModel();
                UserInfo user = new UserInfo() { Id = 1, Name = "Jsey" };

不能既是基类约束,又是引用类型约束

接口约束不常用,作为了解使用,应用的实际类型必须实现该接口。

   public class UserInfo : ModelBase, IBase
    {
        public void Show()
        {
            Console.WriteLine("SHow Info");
        }
    }

于是我们在使用的时候,就会有限制——

 model.ShowInfo<UserInfo>(user);
model.ShowInfo<string>("sss");//不行  string 不是ModelBase派生而来的

创建基类约束的时候,内容可以什么都不写,它其实就是用来限制哪个泛型T的类型(该基类的派生类)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Matrix Y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值