Generic Programming
Tags: generics, genericprogramming, oop, csharp
Published: 2021-02-10 17:53:43


Generics and generic programming are some of the most powerful techniques that developers use to write clean and reusable code. In this article, we are going to be looking at what generic programming is, how it can be applied and why you should start maximizing its power. Before we get our hands dirty on some code lets us look into some ground concepts.

##What is Generic Programming##
Generic programming is a style of programming in which the types of the objects or variables can be specified at a later time. It allows developers to write code in such a way where the types are parameters.
Some advantages of generics include:
* Code reuse
* It prioritizes type safety
* It also reduces the need to cast an object to other types

_NOTE_: Dynamically typed programming languages do not have generics. For example javascript, you can create a function and the parameters will work with any type. So this concept is mostly for strongly typed programming languages like java and c#.

The implementation is going to be in c# but this concept is widely used in a lot of strongly-typed programming languages. So let’s go on.

Let’s consider a response model for API endpoints. It will be used as a structure for how all our API responses should look like.
```c#
public class Response<T> 
	{
		public bool Successful { get; set; }

		public string Message { get; set; }

		public  T  Data { get; set; }
		public  IEnumerable<T>  DataList { get; set; }

	}                                                              

```

_In the code above the `<T>` stands for the generic parameter. As you will see we would be able to pass any type of our choice to the class instantiation to determine what the type of the variable Data and DataList will be. So let us use the model on a simple API endpoint._



```c#
[HttpGet]
        public IActionResult GetItems()
        {
            var result = item.GetItems();
            return Ok(new Response<Item>
            {
                Successful = true,
                DataList = result,
                Data = null,
                Message = "operation sucessfull"
            });
        }
```
_Inside the ok return statement, we pass the response to the item with the response model we created before and passing a type of `item` (this is an entity type that was created) into the response object inside the arrow ‘<>’ brackets._
```c#
public IActionResult Detail(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
            var result = ops.GetSub(id);
            return Ok(new Response<subTasks>
            {
                Data = result,
                Message = "Operation Successful",

            });
        }
```


_Now in the code above you see we used the same response model and passed in the type parameter into the arrow brackets “<>”, but of a different type of ‘subtask’. The response model is very reusable. 
This is a very simple way of implementing generics in c#. we can do a lot more, lets look into how generics can improve abstractions. In the next example, we would look into what we call a generic repository._
So let us consider this interface.
```c#
public interface IRepository<T> where T: class
    {
        Task<int> Count { get; }
        Task<T> Add(T item);
        Task<bool> Remove(T item);
        Task<IQueryable<T>> GetBy(Func<T, bool> predicate);
        Task<T> Update(T entity);
        Task<T> GetById(object id);
        
   }
```
_And this is the implementation_


```c#
private DbContext<IdentityUser> _dbContext;
        public Repository(DbContext<IdentityUser> dbContext)
        {
            _dbContext = dbContext;
        }

      

        public async Task<T> Add(T item)
        {
            await _dbContext.AddAsync<T>(item);
            int count = _dbContext.SaveChanges();
            if (count < 1)
            {
                return null;
            }
            return item;
        }


        public async Task<IQueryable<T>> GetAll()
        {
            var allItem = await Task.Run(() => _dbContext.Set<T>().AsQueryable());
            return allItem;
        }
        public async Task<T> GetById(object id)
        {
            return await _dbContext.Set<T>().FindAsync(id);
        }

        public async Task<bool> Remove(T item)
        {
            _dbContext.Set<T>().Remove(item);
            int count = await _dbContext.SaveChangesAsync();
            if (count < 1) { return false; }
            return true;
        }

        public async Task<T> Update(T entity)
        {
            _dbContext.Entry<T>(entity).State = EntityState.Modified;
            int count = _dbContext.SaveChanges();
            if (count < 1)
            {
                return null;
            }
            return entity;
        }

    }
```


The `<T>` in the methods stand as the type parameters.


```c#
public class StudentService : IStudentService {
    private readonly IRepository<student> _repo;
    public StudentService (IRepository<student> repo) {
        _repo = repo;
    }
    public async Task<List<student>> GetAll () {
        var result = await _repo.GetAll ();
        return result;
    }
    public async Task<student> GetById (int id) {
        var res = await _repo.GetById (id);
        return res;
    }
    public async Task < (bool success, string message) > Create (student obj) 
    {
        var resVal = await _repo.Add (entity);
        if (resVal.Id > 1) {
            return (true, "Operation Successful");
        }
        return (false, "Operation not Successful")
    }
    public async Task < (bool success, string message) >Update (student obj) 
    {
        var retVal = await _repo.Update(entity);
        if (retVal.Id > 0) {
            return (true, "Operation Successful");
        }
        return (false, "Operation not Successful")
    }  
}
```
In the code above the generic repository is been used in another service. The `IRepository` implementation can be used in other services with the implementation that we specified, because of generics we can have cleaner abstractions by using a simple implementation for all types.
The point is that we can make better abstractions and make the code more reusable and type-safe. So that’s it on this topic, I am looking forward to seeing how you guys use this technique even in different languages. Please if there anything you didn’t understand put it in the comments I am listening, Have a nice day thank you.