C# сохранить тип класса в качестве препроцессора - PullRequest
0 голосов
/ 09 марта 2020

Можно ли в C# сохранить тип класса как директиву препроцессора, как в C / C ++?

У меня есть несколько служб с большим количеством общего кода. Основное различие заключается в правильном наборе DbSet и использовании правильного класса.

От следующего кода до:

public class TaxService
{
    readonly DatabaseContext db;

    public TaxService(DatabaseContext database)
    {
        db = database;
    }

    public async Task<string> DeleteAsync(int? id)
    {
        if (await db.Taxes.FindAsync(id) is Tax tax)
        {
            string title = tax.Name;

            db.Taxes.Remove(tax);

            try
            {
                await db.SaveChangesAsync();

                return title;
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        return null;
    }

    public async Task<List<Tax>> GetAllAsync()
    {
        return await db.Taxes.AsNoTracking().ToListAsync();
    }
}

К примеру:

public class TaxService<T> where T : Tax
{
    readonly DatabaseContext db;

    DbSet<Tax> dbSet => db.Tax;

    public TaxService(DatabaseContext database)
    {
        db = database;
    }

    public async Task<string> DeleteAsync(int? id)
    {
        if (await dbSet.FindAsync(id) is T tax)
        {
            string title = tax.Name;

            dbSet.Remove(tax);

            try
            {
                await db.SaveChangesAsync();

                return title;
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        return null;
    }

    public async Task<List<T>> GetAllAsync()
    {
        return await dbSet.AsNoTracking().OfType<T>().ToListAsync();
    }
}

Из c есть проблема в дизайне выше. Когда я пытаюсь вызвать TaxService, я должен передать Tax класс через generi c type => TaxService<Tax>

Также в методе GetAllAsync я должен использовать метод OfType, чтобы избежать компиляции ошибки. Невозможно вернуть List<Tax> как List<T>

Есть предложения по разработке шаблона? Спасибо

РЕДАКТИРОВАТЬ (ответ в МБ):

public class TaxService : TaxService<Tax>
{
    public TaxService(DatabaseContext database) : base(database)
    {
    }
}

public class TaxService<T> where T : Tax

1 Ответ

1 голос
/ 09 марта 2020

Я однажды построил базовый контроллер.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;

namespace DataAccessLayer.Controllers
{
    public class BaseController<TEntity> where TEntity : class, new()
    {
        public virtual TEntity Get<TContext>(Expression<Func<TEntity, bool>> predicate, TContext context) where TContext : DbContext
        {
            var item = context.Set<TEntity>().FirstOrDefault(predicate);
            return item;
        }

        public List<TEntity> GetList<TContext>(Expression<Func<TEntity, bool>> predicate, TContext context) where TContext : DbContext
        {
            var item = context.Set<TEntity>().Where(predicate).ToList();
            return item;
        }

        public IQueryable<TEntity> GetListQueryable<TContext>(Expression<Func<TEntity, bool>> predicate, TContext context) where TContext : DbContext
        {
            var item = context.Set<TEntity>().Where(predicate);
            return item;
        }

        public List<TEntity> GetAll<TContext>(TContext context) where TContext : DbContext
        {
            var item = context.Set<TEntity>().ToList();
            return item;
        }

        public IEnumerable<TEntity> GetAllEnumerable<TContext>(TContext context) where TContext : DbContext
        {
            IEnumerable<TEntity> item = context.Set<TEntity>();
            return item;
        }


        public virtual TEntity Update<TContext>(TEntity input, Expression<Func<TEntity, bool>> predicate, TContext context) where TContext : DbContext
        {
            if (input == null)
                return null;

            var existing = context.Set<TEntity>().FirstOrDefault(predicate);

            if (existing != null) context.Entry(existing).CurrentValues.SetValues(input);

            return existing;
        }


        public virtual TEntity Insert<TContext>(TEntity input, TContext context) where TContext : DbContext
        {
            context.Set<TEntity>().Add(input);

            return input;
        }

    }
}

вы используете его, создавая контроллер следующим образом:

public class TaxcController : BaseController<Tax>
    {
    }

, а затем просто создавая экземпляр. Таким образом, у вас есть контроллер или репо для создания ваших перегрузок или уникальных методов, когда нужно что-то «выключить».

public void dostuff()
{
    TaxController taxController = new TaxController();
    taxController.Insert(item, context);

}

Это очень полезно при работе с базой данных, которая имеет был построен пьяным программистом в спешке, потому что все, что следует тому же шаблону, может быть использовано, и все, что не может все еще использоваться через контроллер, контроллер просто становится ответственным за "обход" с любыми исключениями там существует в базе данных.

Это всего лишь Po C, вам не обязательно делать это именно так. Просто чтобы начать работать.

...