How can I get an instance of a class when I only have the string name of the class?

Viewed 47

I have several IRepositories and server Repositories. I'm trying to make these repositories generic so I can use the _unitOfWork pattern. I have developed the IRepository but am having issues in the Repository as I am using DTOs. Possibly, a little code will help.

//T is an instance of T_IFS_EmployeeDTO 
public T Create(T objDTO)
{
    //This worked in the old specfic implementation as I just passed a T_IFS_EmployeeDTO objDTO:
    T_IFS_Employee obj = _mapper.Map<T_IFS_EmployeeDTO, T_IFS_Employee>(objDTO);

    //This is sort of how I see it working in the generic implementation. The baseClass method is below.
    var instanceOfObjClass = baseClass();

    //This is where I need to map the DTO to the instanceOfObjClass
    instanceOfObjClass = _mapper.Map<T, T_IFS_Employee>(objDTO);
    //In the line above, I need to pass the specific class in the place of T_IFS_Employee

    //I also need to use it here...
    var addedObj = _db.T_IFS_Employee.Add(obj);
    _db.SaveChanges();

    //and on the reverse map.
    return _mapper.Map<T_IFS_Employee, T>(addedObj.Entity);
}

This is the implementation that I am attempting to make generic. I am passing the DTO so it would receive a T_IFS_EmployeeDTO obj (objDTO). To do the mapping, I need to be able to specify a T_IFS_Employee obj as well as have the class name for the DB Access. The class standards are to just add DTO to the database class. I can get the name of the class by string baseClass = typeof(T).Name; but that is only a string of the name of the class that I want. baseClass will return an instance of the class but I still need to use the class reference in the _mapper.Map call and in the _db.T_IFS_Employee.Add call. Hopefully, you can see what I am trying to do here and can provide some clarity for my actions.

Am I on the right track and just need a boost or do I have this all wrong. As always, thank you for taking the time and giving your valuable input.

The private method to create an instance:

private object baseClass()
{
    string baseClass = typeof(T).Name;
    baseClass = baseClass.Replace("DTO", "");
    var typeOfClass = Type.GetType(baseClass);
    var expressionOfClass = Expression.New(typeOfClass);
    var typeFactory = Expression.Lambda<Func<dynamic>>(expressionOfClass).Compile();
    return typeFactory();
 }

Okay. I'm sorry but I thought I posted everything that was needed.

This is the current interface that works:

public interface IEmployeeRepository
{
    public T_IFS_EmployeeDTO Create(T_IFS_EmployeeDTO objDTO);
    public T_IFS_EmployeeDTO Update(T_IFS_EmployeeDTO objDTO);
    public int Delete(int id);
    public T_IFS_EmployeeDTO Get(int id);
    public IEnumerable<T_IFS_EmployeeDTO> GetAll();
}

And this is the current implementation that works.

public class EmployeeRepository : IEmployeeRepository
{
    private readonly ApplicationDbContext _db;
    private readonly IMapper _mapper;
    public EmployeeRepository(ApplicationDbContext db, IMapper mapper)
    {
        _db = db;
        _mapper = mapper;
    }
    public T_IFS_EmployeeDTO Create(T_IFS_EmployeeDTO objDTO)
    {
        T_IFS_Employee obj = _mapper.Map<T_IFS_EmployeeDTO, T_IFS_Employee>(objDTO);
        var addedObj = _db.T_IFS_Employee.Add(obj);
        _db.SaveChanges();
        return _mapper.Map<T_IFS_Employee, T_IFS_EmployeeDTO>(addedObj.Entity);
    }

    public int Delete(int id)
    {
        var obj = _db.T_IFS_Employee.FirstOrDefault(u => u.EmployeeID == id);
        if (obj != null)
        {
            _db.T_IFS_Employee.Remove(obj);
            return _db.SaveChanges();
        }
        return 0;
    }

    public T_IFS_EmployeeDTO Get(int id)
    {
        var obj = _db.T_IFS_Employee.FirstOrDefault(u => u.EmployeeID == id);
        if (obj != null)
        {
            return _mapper.Map<T_IFS_Employee, T_IFS_EmployeeDTO>(obj);
        }
        return new T_IFS_EmployeeDTO();
    }

    public IEnumerable<T_IFS_EmployeeDTO> GetAll()
    {
        return _mapper.Map<IEnumerable<T_IFS_Employee>, IEnumerable<T_IFS_EmployeeDTO>>(_db.T_IFS_Employee);
    }

    public T_IFS_EmployeeDTO Update(T_IFS_EmployeeDTO objDTO)
    {
        var objFromDb = _db.T_IFS_Employee.FirstOrDefault(u => u.EmployeeID == objDTO.EmployeeID);

        if (objFromDb != null)
        {
            _mapper.Map(objDTO, objFromDb);
            _db.SaveChanges();
            return _mapper.Map<T_IFS_Employee, T_IFS_EmployeeDTO>(objFromDb);
        }
        return objDTO;
    }
}

I'm trying to implement a generic interface and generic repository because I have about 9 of these that are almost identical.

I have setup the following generic interface that seems to be correct:

public interface IRepository<T> where T : class
{
    public T Create(T objDTO);
    public T Update(T objDTO);
    public int Delete(int id);
    public T Get(int id);
    public IEnumerable<T> GetAll();
    T GetFirstOrDefault(Expression<Func<T, bool>>? filter = null);
}

But I'm having trouble in the implementation:

This includes some of the things I was trying to get to work so it's a little messy. I was trying to add some things to the constructor that I might be able to use in the methods. You can probably ignore that. I'm trying to get the Create method to work. As you can see in that method, I need the additional class of T_IFS_Employee. I have the T_IFS_EmployeeDTO class as the objDTO was passed. I am so sorry if this is not clear. I appreciate the time you have taken but if I knew exactly how I needed to do this, I would probably not be here. I have researched adding two classes to the interface but that does not seem to be an option.

public class Repository<T> : IRepository<T> where T : class
{
    private readonly ApplicationDbContext _db;
    private readonly IMapper _mapper;
    internal DbSet<T> _dbSet;
    private readonly Type _type;
    private readonly string _typeName;
    private readonly object _typeOfClass;
    private readonly object _expressionOfClass;
    private readonly object _typeFactory;
    public Repository(ApplicationDbContext db, IMapper mapper)
    {
        _db = db;
        _mapper = mapper;
        this._dbSet = db.Set<T>();
        _type = typeof(T);
        _typeName = typeof(T).Name.Replace("DTO", "");
        _typeOfClass = Type.GetType(_typeName);
        _expressionOfClass = Expression.New(_typeOfClass);
        _typeFactory = Expression.Lambda<Func<dynamic>>(_expressionOfClass).Compile();
    }
    public T Create(T objDTO)
    {
        var objClass = baseClassInstance();

        T_IFS_Employee obj = _mapper.Map<T, T_IFS_Employee>(objDTO);
        var addedObj = _db.T_IFS_Employee.Add(obj);
        _db.SaveChanges();
        return _mapper.Map<T_IFS_Employee, T>(addedObj.Entity);
    }

    public int Delete(int id)
    {
        throw new NotImplementedException();
    }

    public T Get(int id)
    {
        throw new NotImplementedException();
    }

    public IEnumerable<T> GetAll()
    {
        throw new NotImplementedException();
    }

    public T GetFirstOrDefault(Expression<Func<T, bool>>? filter = null)
    {
        throw new NotImplementedException();
    }

    public T Update(T objDTO)
    {
        throw new NotImplementedException();
    }

    private object baseClassInstance()
    {
        
        baseClass = baseClass.Replace("DTO", "");
        var typeOfClass = Type.GetType(baseClass);
        var expressionOfClass = Expression.New(typeOfClass);
        var typeFactory = Expression.Lambda<Func<dynamic>>(expressionOfClass).Compile();
        return typeFactory();
    }
}
0 Answers
Related