Masoud
Masoud

Reputation: 8211

Using dynamically created generic interface's methods in c#

I have a generic interface:

public interface IGeneric<T>
{
    Method1(T t);
    Method2(T t);
}

Using following piece of code, I create an instance of IGeneric<T> based on an entity type, dynamically:

var entityType  = entity.GetType();
var genericType = typeof(IGeneric<>).MakeGenericType(entityType);
var result      = Activator.CreateInstance(genericType);

For example if my entity is an Order the result will be IGeneric<Order>. Now, how can I call the result's methods, for example I want to call Method1():

result.Method1();

But the Method1() isn't accessible.

Upvotes: 0

Views: 749

Answers (2)

Ilya Palkin
Ilya Palkin

Reputation: 15787

I think that any IoC container, framework that knows how to resolve types, is something that you are looking for. First open generic types can be registered, then their inmplementations can be resolved.

According to your code block I suggest you use the following approach. It uses Activator to create an instance of Repository<T> that inherits IRepository<T>. IRepository interface provides an ability to cast result to the non-generic type an invoke Insert method without reflection.:

public class GenericInterfaceTests
{
    [Fact]
    public void IncertsStringEntity()
    {
        // Arrange.
        var entity = "100500";

        var entityType = entity.GetType();
        var genericType = typeof(Repository<>).MakeGenericType(entityType);
        var result = Activator.CreateInstance(genericType);

        // Act.
        (result as IRepository).Insert(entity);

        // Assert.
        result.Should().BeOfType<Repository<string>>();
        var repository = result as Repository<string>; 

        repository.DataSource.Should().Contain(entity);
    }

    [Fact]
    public void InsertsIntegerEntity()
    {
        // Arrange.
        var entity = 100500;

        var entityType = entity.GetType();
        var genericType = typeof(Repository<>).MakeGenericType(entityType);
        var result = Activator.CreateInstance(genericType);

        // Act.
        (result as IRepository).Insert(entity);

        // Assert.
        result.Should().BeOfType<Repository<int>>();
        var repository = result as Repository<int>; 

        repository.DataSource.Should().Contain(entity);
    }
}

public interface IRepository<TEntity>
{
    void Insert(TEntity entity);
}

public interface IRepository
{
    void Insert(object entity);
}

public class Repository<TEntity> : IRepository<TEntity>, IRepository
{
    public List<TEntity> DataSource { get; set; }

    public Repository()
    {
        DataSource = new List<TEntity>();
    }

    public void Insert(TEntity entity)
    {
        DataSource.Add(entity);
    }

    void IRepository.Insert(object entity)
    {
        Insert((TEntity)entity);
    }
}

Upvotes: 0

Markus
Markus

Reputation: 22481

The following sample shows how to call methods that are located in a generic interface:

using System;

public interface IMyInterface<T>
{
    T Method1(T input);
}

public class MyImpl : IMyInterface<int>
{
    public int Method1(int input)
    {
        return input * 2;
    }
}

public class Test
{
    public static void Main()
    {
        // Concrete type that implements the interface
        Type implType = typeof(MyImpl);
        // Type of generic interface
        Type genType = typeof(IMyInterface<>);
        // Interface for int
        Type concType = genType.MakeGenericType(typeof(int));
        // Create instance
        object inst = Activator.CreateInstance(implType);
        // Retrieve member that you want to call
        var member = concType.GetMethod("Method1");
        // Invoke member on instance
        var result = member.Invoke(inst, new object[] { 123 });
        Console.WriteLine("{0} --> {1}", 123, result);
    }
}

You can run and edit the sample here.

Upvotes: 1

Related Questions