tags:

views:

363

answers:

4
+1  Q: 

DRY this method

I need help making this method generic. It is repeated about ten times to get lists for different web list controls (substituting "MyType" for the type used in the particular control).

    private static IList<MyType> GetList(RequestForm form)
    {
        // get base list
        IMyTypeRepository myTypeRepository = new MyTypeRepository(new HybridSessionBuilder());
        IList<MyType> myTypes = myTypeRepository.GetAll();

        // create results list
        IList<MyType> result = new List<MyType>();

        // iterate for active + used list items
        foreach (MyType myType in myTypes)
        {
            if (myType.Active || form.SolutionType.Contains(myType.Value))
            {
                result.Add(myType);
            }
        }

        // return sorted results
        result.OrderBy(o => o.DisplayOrder);
        return result;
    }

Let me know if this isn't enough information. I think this requires more advanced language features that I'm just getting acquainted with. Maybe I should make them all use the same repository?

Thanks for your help.

EDIT: Thanks for your help. I don't have any peer support, so this board is fantastic and I learned something from each of you. I wish I could accept all the answers.

+4  A: 

If all the types implement the same interface, (if they don't then make them, and make sure to add all the properties to the interface that are needed in this method) then you can do something like this:

private static IList<T> GetList(RequestForm form)
       where T: IMyInterface
    {
        // get base list
        IMyTypeRepository myTypeRepository = new MyTypeRepository(new HybridSessionBuilder());
        IList<T> myTypes = myTypeRepository.GetAll();

        // create results list
        IList<T> result = new List<T>();

        // iterate for active + used list items
        foreach (T myType in myTypes)
        {
            if (myType.Active || form.SolutionType.Contains(myType.Value))
            {
                result.Add(myType);
            }
        }

        // return sorted results

        return result.OrderBy(o => o.DisplayOrder).ToList();
    }

One other change I made is the last line, where you had the orderby on a seperate line and were never actually capturing the Ordered list.

EDIT: To solve the repository problem, you can have a repository factory of sorts that returns the correct repository based on the type of T:

public static IMyTypeRepository  GetRepository(Type t)
{
   if(t == typeof(Type1))
   {
      return Type1Repository();
   }

   if(t == typeof(Type2))
   {
      return Type2Repository();
   }
   .......
}

Assuming of course that all your repositories implement the IMyRepository interface.

BFree
Thanks for catching the order by; hadn't got that far in testing.All the types implement the same interface, but use their own repositories. I would have to make them all use the same repository for this, yes?
Leslie
Well, not necessarily. You can have some kind of Factory that creates the repository based on the type of T. See my Edit.
BFree
+1  A: 

Assuming that the repositories share a common interface, the issue with the repository should be easy to fix: add a static function such as


public static IRepository RepositoryForType(Type t)
{
    if(t == typeof(SomeClass))
       return new SomeClassRepository(new HybridSession());
    else if ...
    else throw new InvalidOperationException("No repository for type " + t.Name);
}

This should require you the least amount of changes to your existing code, but mind that in the future you'll have to add classes support for new repositories in this function as you add new repositories in your project (if you're using unit testing you'll easily figure out if you forgot about this helper anyway).

emaster70
Thanks for this idea. I'm thinking it might be better in this instance to have all the web controls use the same repository, especially since they all come from the same db table.
Leslie
+5  A: 

You could firstly make your function a bit more terse like this:

private static IList<MyType> GetList(RequestForm form)
{
    // get base list
    IMyTypeRepository myTypeRepository =
        new MyTypeRepository(new HybridSessionBuilder());

    IList<MyType> myTypes = myTypeRepository.GetAll();

    return myTypes.Where(x => x.Active || form.SolutionType.Contains(x.Value))
                  .OrderBy(x => x.DisplayOrder).ToList();
}

At that point, most of the content of the function is directly related to MyType, so how you can further improve it depends largely on how MyType relates to the other types involved. For example, here is a hypothetical version that you could write if your other types followed a reasonable-looking (to me) contract:

private static IList<T> GetList(RequestForm form) where T : OrderedValueContainer
{
    // we'll want to somehow genericize the idea of a TypeRepository that can
    // produce these types; if that can't be done, we're probably better off
    // passing a repository into this function rather than creating it here

    var repository = new TypeRepository<T>(new HybridSessionBuilder());
    IList<T> myTypes = repository.GetAll();

    // the hypothetical OrderedValueContainer class/interface
    // contains definitions for Active, Value, and DisplayOrder

    return myTypes.Where(x => x.Active || form.SolutionType.Contains(x.Value))
                  .OrderBy(x => x.DisplayOrder).ToList();
}
mquander
Thanks first for making the method more terse; I really like that. All the types inherit the IWebControl interface. I think I can make them all use the same repository.
Leslie
+2  A: 

First of all, all your types must implement a common interface that define properties like Active, Value ...

Also, for what I can tell, there must be a repository interface for all repositories independently of the MyType so that you can use a generic method like this. The GetAll() method should be defined in the IRepository.

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

public class RepositoryFactory
{
    public static IRepository<T> createRepository<T>(ISessionBuilder sb) where T : IMyType
    {
        // create repository
    }
}

public interface IMyType
{
    bool Active { get; }
    string Value { get; }
}

private static IList<T> GetList(RequestForm form) where T : IMyType
{
    // get base list
    IRepository<T> repository = RepositoryFactory.createRepository<T>(new HybridSessionBuilder());
    IList<T> myTypes = repository.GetAll();

    // create results list
    IList<T> result = new List<T>();

    // iterate for active + used list items
    foreach (T myType in myTypes)
    {
        if (myType.Active || form.SolutionType.Contains(myType.Value))
        {
            result.Add(myType);
        }
    }

    // return sorted results
    return result.OrderBy(o => o.DisplayOrder).ToList();
}
bruno conde
I can't type fast enough. :( I was typing the exact same thing, except using an IoC container for the factory.
Mark