Extension methods in .NET are a powerful feature that allows you to add new methods to existing types without modifying their source code or creating a new derived type. They enable you to write cleaner, more readable, and reusable code. In this article, we’ll dive into the world of extension methods, learn how to create them, and explore best practices and real-world examples.
public class AgentRepository : IAgentRepository
{
private readonly SafeCamDbContext _context;
public AgentRepository(SafeCamDbContext context)
{
_context = context;
}
public async Task<List<Agent>> GetAllAgentsAsync()
{
return await _context.Agents.Include(x => x.Positions).ToListAsync();
}
public async Task<List<Position>> GetAllPositionsAsync()
{
return await _context.Positions.ToListAsync();
}
public async Task<Agent> GetAgentByIdAsync(int id)
{
return await _context.Agents.FirstOrDefaultAsync(x => x.Id == id);
}
public async Task AddAgentAsync(Agent agent)
{
await _context.Agents.AddAsync(agent);
await _context.SaveChangesAsync();
}
public async Task UpdateAgentAsync(Agent agent)
{
_context.Agents.Update(agent);
await _context.SaveChangesAsync();
}
public async Task DeleteAgentAsync(Agent agent)
{
_context.Agents.Remove(agent);
await _context.SaveChangesAsync();
}
}
**
What Are .NET Extension Methods?
**
Extension methods are static methods that can be invoked as if they were instance methods of the extended type. They’re particularly useful for:
Reducing code duplication.
Enhancing readability.
Adding utility methods to types you don’t own (e.g., framework types).
For example, you can add a ToTitleCase method to the string class to convert a sentence into title case without altering the string class itself.
public class AgentService : IAgentService
{
private readonly IAgentRepository _agentRepository;
private readonly IMapper _mapper;
private readonly IWebHostEnvironment _env;
public AgentService(IAgentRepository agentRepository, IMapper mapper, IWebHostEnvironment env)
{
_agentRepository = agentRepository;
_mapper = mapper;
_env = env;
}
public async Task<List<Agent>> GetAllAgentsAsync()
{
return await _agentRepository.GetAllAgentsAsync();
}
public async Task<List<Position>> GetAllPositionsAsync()
{
return await _agentRepository.GetAllPositionsAsync();
}
public async Task<ServiceResult> CreateAgentAsync(AgentCreateDto dto)
{
if (dto.File == null || !dto.File.ContentType.Contains("image") || dto.File.Length > 2 * 1024 * 1024)
{
return new ServiceResult { Success = false, Message = "Invalid file." };
}
dto.ImgUrl = dto.File.Upload(_env.WebRootPath, "\Upload\Agents\");
var agent = _mapper.Map<Agent>(dto);
await _agentRepository.AddAgentAsync(agent);
return new ServiceResult { Success = true };
}
public async Task<AgentUpdateDto> GetAgentForUpdateAsync(int id)
{
var agent = await _agentRepository.GetAgentByIdAsync(id);
return agent == null ? null : _mapper.Map<AgentUpdateDto>(agent);
}
public async Task<ServiceResult> UpdateAgentAsync(AgentUpdateDto dto)
{
var agent = await _agentRepository.GetAgentByIdAsync(dto.PositionId);
if (agent == null)
{
return new ServiceResult { Success = false, Message = "Agent not found." };
}
if (dto.File != null)
{
if (!dto.File.ContentType.Contains("image"))
{
return new ServiceResult { Success = false, Message = "Invalid file type." };
}
if (!string.IsNullOrEmpty(agent.ImgUrl))
{
FileExtension.DeleteFile(_env.WebRootPath, "\Upload\Agents\", agent.ImgUrl);
}
agent.ImgUrl = dto.File.Upload(_env.WebRootPath, "\Upload\Agents\");
}
agent.Name = dto.Name;
await _agentRepository.UpdateAgentAsync(agent);
return new ServiceResult { Success = true };
}
public async Task<bool> DeleteAgentAsync(int id)
{
var agent = await _agentRepository.GetAgentByIdAsync(id);
if (agent == null)
{
return false;
}
if (!string.IsNullOrEmpty(agent.ImgUrl))
{
FileExtension.DeleteFile(_env.WebRootPath, "\Upload\Agents\", agent.ImgUrl);
}
await _agentRepository.DeleteAgentAsync(agent);
return true;
}
}
How to Create an Extension Method
Creating an extension method is straightforward. Here’s a step-by-step guide:
Define a Static Class
The class that holds your extension methods must be static.
Write a Static Method
The method itself must be static and take the type you want to extend as the first parameter, prefixed with the this keyword.
public class AgentController : Controller
{
private readonly IAgentService _agentService;
public AgentController(IAgentService agentService)
{
_agentService = agentService;
}
public async Task<IActionResult> Index()
{
var agents = await _agentService.GetAllAgentsAsync();
return View(agents);
}
[HttpGet]
public async Task<IActionResult> Create()
{
ViewBag.Positions = await _agentService.GetAllPositionsAsync();
return View();
}
[HttpPost]
public async Task<IActionResult> Create(AgentCreateDto dto)
{
if (!ModelState.IsValid)
{
ViewBag.Positions = await _agentService.GetAllPositionsAsync();
return View(dto);
}
var result = await _agentService.CreateAgentAsync(dto);
if (!result.Success)
{
ModelState.AddModelError("File", result.Message);
ViewBag.Positions = await _agentService.GetAllPositionsAsync();
return View(dto);
}
return RedirectToAction("Index");
}
[HttpGet]
public async Task<IActionResult> Update(int id)
{
var dto = await _agentService.GetAgentForUpdateAsync(id);
if (dto == null)
{
return NotFound();
}
ViewBag.Positions = await _agentService.GetAllPositionsAsync();
return View(dto);
}
[HttpPost]
public async Task<IActionResult> Update(AgentUpdateDto dto)
{
if (!ModelState.IsValid)
{
ViewBag.Positions = await _agentService.GetAllPositionsAsync();
return View(dto);
}
var result = await _agentService.UpdateAgentAsync(dto);
if (!result.Success)
{
ModelState.AddModelError("File", result.Message);
ViewBag.Positions = await _agentService.GetAllPositionsAsync();
return View(dto);
}
return RedirectToAction("Index");
}
[HttpDelete]
public async Task<IActionResult> Delete(int id)
{
var success = await _agentService.DeleteAgentAsync(id);
if (!success)
{
return NotFound();
}
return RedirectToAction("Index");
}
}
.NET extension methods are a simple yet powerful tool for writing cleaner and more maintainable code. By following best practices and leveraging them effectively, you can enhance the functionality of existing types and improve the overall quality of your projects.
What are your favorite use cases for extension methods? Share your thoughts in the comments below!
public interface IRepository<TEntity> where TEntity : BaseEntity, new()
{
DbSet<TEntity> Table { get; }
Task<TEntity?> GetByIdAsync(int id, params Expression<Func<TEntity, object>>[] includes);
IQueryable<TEntity> GetAll(params Expression<Func<TEntity, object>>[] includes);
IQueryable<TEntity> FindAll(Expression<Func<TEntity, bool>> predicate, params Expression<Func<TEntity, object>>[] includes);
Task<TEntity> AddAsync(TEntity entity);
Task UpdateAsync(TEntity entity);
Task DeleteAsync(TEntity entity);
}
Top comments (0)