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() { }
原文地址:https://www.cnblogs.com/Xieyiincuit/p/14327512.html