Factory Method and Generics

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 will have several implementations that return different Entity Framework data. At some point, I want to present the user with a list of classes that implement the IRepository interface. I am doing 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 sets a specific string, return a specific repository type and allow me to call the GetAll method. In pseudo code:

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

(I know this will not work, because I have to specify a specific type in the factory method).

I need this functionality because I want to give the user the ability to bind a report to a specific data source. Thus, they can start a new report in which the report data source is associated (for example) with the TrendDataRepository.GetAll () method.

However, it may be because the end of the world is approaching ;-) or on Friday afternoon, and I just can’t think anymore, I don’t know how to implement this.

Some pointers will really be welcome.

+6
source share
1 answer

I would suggest returning a collection of repository types instead of names and just display the names in the user interface:

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

Then, when the user selects a source you can do:

 object repository = Activator.CreateInstance(selectedType); 

This method requires each repository to have a default constructor.

Activator.CreateInstance return the object, and you cannot pass it to your IRepository<T> interface if you do not know the typical type of T that you expect. The best solution is probably to create a non-generic IRepository interface that also implements your repository classes:

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

Now you can create created repositories on IRepository :

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

you can create a base repository class that 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(); } } 
+2
source

All Articles