Frage

I have the following interface and implementation:

public interface IRepository<T>
{
    IList<T> GetAll();
}

internal class TrendDataRepository : IRepository<TrendData>
{
    public IList<TrendData> GetAll()
    {
        //.. returns some specific data via Entity framework
    }
}

I'm going to have multiple implementations that all return different data by Entity Framework. At some point I want to represent the user a list of classes that implement the IRepository interface. I do this with the following code. This works great for me.

    public static IEnumerable<string> GetAvailableRepositoryClasses()
    {
        var repositories = from t in Assembly.GetExecutingAssembly().GetTypes()
                           where t.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof (IRepository<>))
                           select t.Name;

        return repositories;
    }

However, I would also like to create a factory method that given a specific string will return a concrete Repository type and allow me to call the 'GetAll' method on it. In pseudo-code:

someObject = Factory.CreateInstance("TrendData");
someObject.GetAll();

(I know this won't work because I have to specify a concrete type in the factory method).

I desire this functionality because I want to give a user the ability to bind a report to a specific datasource. This way they can start a new report where the datasource of the report is bound to (for example) the TrendDataRepository.GetAll() method.

However, maybe because the end of the world is getting near ;-) or it's Friday afternoon and I just can't think clearly any more, I don't know how to realise this.

Some pointers would be really welcomed.

War es hilfreich?

Lösung

I'd suggest returning the collection of repository types instead of the names and just displaying the names in the UI:

public static IEnumerable<Type> GetAvailableRepositoryClasses()
{
    return Assembly.GetExecutingAssembly().GetTypes()
        .Where(t => t.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof (IRepository<>)));
}

Then when a user selects the source you can do:

object repository = Activator.CreateInstance(selectedType);

This method requires each repository to have a default constructor.

Activator.CreateInstance return an object, and you can't cast it to your IRepository<T> interface unless you know the generic type T you're expecting. The best solution is probably to create a non-generic IRepository interface which your repository classes also implement:

public interface IRepository
{
    IList<object> GetAll();
}

Now you can cast your created repositories to IRepository:

IRepository repository = (IRepository)Activator.CreateInstance(selectedType);

you might to create a repository base class which implements both:

public abstract class RepositoryBase<T> : IRepository<T>, IRepository
{
    public abstract IList<T> GetAll();
    IList<object> IRepository.GetAll()
    {
        return this.GetAll().Cast<object>().ToList();
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top