C# Extension Methods

C# Extension Methods

In this week's newsletter we will take a closer look at extension methods in C#. By the end of this article you should be able to:

  1. What are extension methods?
  2. What problem does it solve?
  3. Sample application using extension method

What is C# extension methods?

It is method is a static method that can be used to add additional functionalities without changing the original definition.

It allows you to add functionalities that you may not be able to inherit may be because the class is sealed or you are using a third party library where you don't have the source code.

You can add extension methods to built in class/interface or custom class/interface.

What problem does it solve?

Extension methods in C# can solve several problems in both classes and interfaces:

  1. Enhancing Existing Types: Extension methods allow you to add methods to existing classes or interfaces without modifying their source code or creating derived types. This is particularly useful when you want to add functionality to a class or interface from a library or a framework that you can't or don't want to modify.
  2. Improving Readability: Extension methods can make your code more readable and intuitive. They allow you to write methods that look like instance methods of a class or interface, which can be more intuitive to use than static methods.
  3. Providing Default Implementations (for Interfaces): While C# doesn't support default implementations in interfaces (unlike some other languages such as Java), you can use an extension method to provide a default implementation for an interface method. This can be useful when you want all or most implementations of an interface to use the same method implementation.
  4. Adding Functionality to Interfaces: If you want to add new methods to an interface without breaking existing implementations, you can use extension methods. This allows you to add functionality to an interface without affecting classes that already implement the interface.

Remember, while extension methods can be very useful, they should be used judiciously. Overuse of extension methods can lead to code that is difficult to understand and maintain.

Review of previous post

In this sample we will use the existing EFCoreDemo in our previous post.

A small review of what has been done in the sample application so far.

This is a sample application based on clean architecture. The code is divided into three projects namely.

  • SocialNetworkingAPI as starter project containing controller code.
  • Domain project contains code for entity.
  • Persistence containing code for database migrations.

  1. This code is an end to end working web api. The application is SocialNetworkingAPI where User as an entity.
  2. The User table is created in the SQLite database using Entity core framework.
  3. Data is inserted using Seed class when application loads.
  4. Then the user entity can be retrieved though rest endpoint using GetUsers() and GetUser(id) action methods in controller.

The detailed explanation of code is available in my LinkedIn article here.

We will use extension methods on the Program.cs class of the EFCoreDemo.

Sample Application

We have the following existing Program.cs class in SocialNetworkingAPI folder as shown below:

using Application;
using Microsoft.EntityFrameworkCore;
using Persistence;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<DataContext>(opt =>
{
    opt.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection"));
});

builder.Services.AddMediatR
(
    cfg => cfg.RegisterServicesFromAssemblies(typeof(ListUsers.Handler).Assembly
));

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();
// When we are done with this scope will be disposed and cleaned for memory
// good developer automatically disposes of the scope
using var scope = app.Services.CreateScope();
var services = scope.ServiceProvider;
try
{
    var context = services.GetRequiredService<DataContext>();
    await context.Database.MigrateAsync();
    await Seed.SeedData(context);

}
catch (Exception ex)
{
    var logger = services.GetRequiredService<ILogger<Program>>();
    logger.LogError(ex, "An error occured during migration");
}
app.Run();        

We will move the code for builder to another extension method.

Create a folder called extension as shown below:

Create a class called ApplicationExtensions.cs as shown above. Copy all the services.builder code from Program.cs file. Make the class static and add a static method called AddApplicationServices as shown below:

using Application;
using Microsoft.EntityFrameworkCore;
using Persistence;

namespace SocialNetworkingAPI.Extensions
{
    public static class ApplicationExtensions
    {
        public static IServiceCollection AddApplicationServices(this IServiceCollection services, WebApplicationBuilder builder)
        {
            services.AddControllers();
            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
            services.AddEndpointsApiExplorer();
            services.AddSwaggerGen();
            services.AddDbContext<DataContext>(opt =>
            {
                opt.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection"));
            });
            

            services.AddMediatR
            (
                cfg => cfg.RegisterServicesFromAssemblies(typeof(ListUsers.Handler).Assembly)
            );

            return services;
        }
        
    }
}        

Now rename builder.services to services parameter that takes type IServiceCollection. So, here we have created an extension method that takes the parameter of type this IServiceCollection. Which means when we call builder.services we will have AddApplicationServices() where we can pass the builder argument. This is an example of Extension Method Dependency Registration where we have moved builder.services dependencies into an extension method and then invoking that extension method within the Program file.

The full repository is available here.





Custom Extension Methods in C# enable extending existing classes or interfaces without modifying their original code, enhancing code readability, maintainability, and promoting code reusability. Embrace this powerful feature for cleaner, more scalable code. #CSharp #ProgrammingTips

回复

要查看或添加评论,请登录

社区洞察

其他会员也浏览了