• C# 泛型


    泛型的基本特点:

    1. 可重用性

        基于面向对象的编程思路,我们提高代码复用的基本方法有继承以及多态。那么泛型模板对于我们代码重用又有多高的提升呢?

        假如我们要对订单信息和用户信息进行增删改查的基本管理,那我们可以编写两个接口并实现他们,但写完我们可能会发现,他们的基本核心功能是几乎相同的,我们花了双倍的时间写了两份几乎一样的代码,那如果还有其他模块的信息需要管理呢?我们也就一直这样写下去明显不是正确的做法,这个时候我们应该引入泛型。

        如下创建一个基础的泛型基类:

    public class Repository<T> : IRepository<T> where T : class
        {
            protected DbContext _context;
    
            public Repository(DbContext dbContext)
            {
                _context = dbContext;
            }
    
            public IEnumerable<T> GetAll()
            {
                return _context.Set<T>();
            }
    
            public virtual async Task<IEnumerable<T>> GetAllAsyn()
            {
    
                return await _context.Set<T>().ToListAsync();
            }
    
            public virtual T Get(int id)
            {
                return _context.Set<T>().Find(id);
            }
    
            public virtual async Task<T> GetAsync(int id)
            {
                return await _context.Set<T>().FindAsync(id);
            }
    
            public virtual T Add(T t)
            {
                _context.Set<T>().Add(t);
                _context.SaveChanges();
                return t;
            }
    
            public virtual async Task<T> AddAsyn(T t)
            {
                _context.Set<T>().Add(t);
                await _context.SaveChangesAsync();
                return t;
            }
    
            public virtual T Find(Expression<Func<T, bool>> match)
            {
                return _context.Set<T>().SingleOrDefault(match);
            }
    
            public virtual async Task<T> FindAsync(Expression<Func<T, bool>> match)
            {
                return await _context.Set<T>().SingleOrDefaultAsync(match);
            }
    
            public IEnumerable<T> FindAll(Expression<Func<T, bool>> match)
            {
                return _context.Set<T>().Where(match).ToList();
            }
    
            public async Task<IEnumerable<T>> FindAllAsync(Expression<Func<T, bool>> match)
            {
                return await _context.Set<T>().Where(match).ToListAsync();
            }
    
            public virtual void Delete(T entity)
            {
                _context.Set<T>().Remove(entity);
                _context.SaveChanges();
                
            }
    
            public virtual async Task<int> DeleteAsyn(T entity)
            {
                _context.Set<T>().Remove(entity);
                return await _context.SaveChangesAsync();
            }
    
            public virtual T Update(T t, object key)
            {
                if (t == null)
                    return null;
                T exist = _context.Set<T>().Find(key);
                if (exist != null)
                {
                    _context.Entry(exist).CurrentValues.SetValues(t);
                    _context.SaveChanges();
                }
                return exist;
            }
    
            public virtual async Task<T> UpdateAsyn(T t, object key)
            {
                if (t == null)
                    return null;
                T exist = await _context.Set<T>().FindAsync(key);
                if (exist != null)
                {
                    _context.Entry(exist).CurrentValues.SetValues(t);
                    await _context.SaveChangesAsync();
                }
                return exist;
            }
    
            public int Count()
            {
                return _context.Set<T>().Count();
            }
    
            public async Task<int> CountAsync()
            {
                return await _context.Set<T>().CountAsync();
            }
    
            public virtual void Save()
            {
    
                _context.SaveChanges();
            }
    
            public async virtual Task<int> SaveAsync()
            {
                return await _context.SaveChangesAsync();
            }
    
            public virtual IEnumerable<T> FindBy(Expression<Func<T, bool>> predicate)
            {
                IEnumerable<T> query = _context.Set<T>().Where(predicate);
                return query;
            }
    
            public virtual async Task<IEnumerable<T>> FindByAsyn(Expression<Func<T, bool>> predicate)
            {
                return await _context.Set<T>().Where(predicate).ToListAsync();
            }
        }
    View Code

        这样我们就完成了一个基础的模板,当我们要构造某个模块的功能时,我们只需将实体通过泛型参数传入即可获取所有的基本功能。同时,由于基类中的方法都是虚方法,这里也可以对其进行重写。


        2. 类型安全性

        泛型将类型安全的负担从你那里转移到编译器。 没有必要编写代码来测试正确的数据类型,因为它会在编译时强制执行。 降低了强制类型转换的必要性和运行时错误的可能性。

        

        如我构造了一个泛型参数为string的列表,当我想插入其他类型的数据时,这个时候是不被允许的。


      3. 性能与效率

        以下一个例子比较了普通方法,Object参数类型的方法,泛型方法的性能。让三种方法执行相同的操作,比较用时长短。 

    public class Monitor
            {
                public static void Show()
                {
                    Console.WriteLine("****************Monitor******************");
                    {
                        int iValue = 12345;
                        long commonSecond = 0;
                        long objectSecond = 0;
                        long genericSecond = 0;
    
                        {
                            Stopwatch watch = new Stopwatch();
                            watch.Start();
                            for (int i = 0; i < 100000000; i++)
                            {
                                ShowInt(iValue);
                            }
                            watch.Stop();
                            commonSecond = watch.ElapsedMilliseconds;
                        }
                        {
                            Stopwatch watch = new Stopwatch();
                            watch.Start();
                            for (int i = 0; i < 100000000; i++)
                            {
                                ShowObject(iValue);
                            }
                            watch.Stop();
                            objectSecond = watch.ElapsedMilliseconds;
                        }
                        {
                            Stopwatch watch = new Stopwatch();
                            watch.Start();
                            for (int i = 0; i < 100000000; i++)
                            {
                                Show<int>(iValue);
                            }
                            watch.Stop();
                            genericSecond = watch.ElapsedMilliseconds;
                        }
                        Console.WriteLine("commonSecond={0},objectSecond={1},genericSecond={2}"
                            , commonSecond, objectSecond, genericSecond);
                    }
                }
    
                
                private static void ShowInt(int iParameter)
                {
                    
                }
                private static void ShowObject(object oParameter)
                {
                    
                }
                private static void Show<T>(T tParameter)
                {
                    
                }
                
            }
    View Code

        

        由结果可以看出,泛型方法的性能最高,其次是普通方法,object方法由于装箱和拆箱导致性能损耗严重,性能最低。


    泛型的形式:

      1. 泛型类  

    public class MyGenericClass<T>
        {
            public T t;
    
            public void Show(T t)
            {
                Console.WriteLine(t + ":"+ typeof(T));
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                MyGenericClass<string> strGenericClass = new MyGenericClass<string>();
                MyGenericClass<int> intGenericClass = new MyGenericClass<int>();
    
                strGenericClass.Show("Hello");
                intGenericClass.Show(1);
                Console.ReadKey();
    
            }
        }

      2. 泛型接口

    using System.Collections.Generic;
    
    namespace MyGeneric
    {
        public interface IGenericInterface<T>
        {
            //泛型类型的返回值
            T GetT(T t);
        }
    }

      在使用泛型接口或者类时,需要指定具体类型。

    namespace MyGeneric
    {
        /// <summary>
        /// 使用泛型的时候必须指定具体类型,
        /// 这里的具体类型是int
        /// </summary>
        public class CommonClass :GenericClass<int>
        {
        }
    }

      如果子类也是泛型,那么继承的时候可以不指定具体类型:

    namespace MyGeneric
    {
        /// <summary>
        /// 使用泛型的时候必须指定具体类型,
        /// 这里的具体类型是int
        /// </summary>
        public class CommonClass :GenericClass<int>
        {
        }
    
        /// <summary>
        /// 子类也是泛型的,继承的时候可以不指定具体类型
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public class CommonClassChild<T>:GenericClass<T>
        {
    
        }
    }

    泛型的约束:

      以下六种为泛型类型的约束:

    where T: struct
    类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型where T : class
    类型参数必须是引用类型;这一点也适用于任何类、接口、委托或数组类型。
    where T:new()
    类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定where T:<基类名>
    类型参数必须是指定的基类或派生自指定的基类。
    where T:<接口名称>
    类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。
    where T:U
    为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。

      使用约束的原因:

      例如,基类约束告诉编译器:仅此类型的对象或从此类型派生的对象才可用作类型参数。一旦编译器有了这个保证,它就能够允许在泛型类中调用该类型的方法。提高功能内聚度,提升隔离度。

      多个参数的约束:

      可以对多个参数应用约束,并对一个参数应用多个约束,如下面的示例所示:

    class Base { }
    class Test<T, U>
        where U : struct
        where T : Base, new() { }
  • 相关阅读:
    service
    Specify the input method type
    添加机型
    高数公式
    MacOS 常用终端命令大全
    Linux-常用命令大全
    Mac系统下利用ADB命令使用
    iOS工程师学习Android开发----AndroidStudio环境准备
    封装socket 到vue2.x 使用
    记录一次因为OutOfMemoryError而发现的Excel文件导入慢的优化思路
  • 原文地址:https://www.cnblogs.com/Xieyiincuit/p/14327512.html
Copyright © 2020-2023  润新知