Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling a function based on parameter type

I am trying to figure out how to simplify the following

let's say I have 2 entity classes

public class A
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string City { get; set; }
}

AND

public class B
{
    public int Id { get; set; } 
    public string Nom { get; set; }
    public string Ville { get; set; }
} 

classes that are similar, but not the same.

each class has a repository classes it uses for CRUD Operations, for example...

public class RepA
{
    public static List<A> GetAll()
    {
        List<A> list = new List<A>();

        A a1 = new A() {Id=1, Name="First A", City="Boston"};
        A a2 = new A() {Id=2, Name="First B", City="Chicago"};
        A a3 = new A() {Id=3, Name="First C", City="San Francisco"};

        list.Add(a1);
        list.Add(a2);
        list.Add(a3);
        return list;
    }

    public static void SaveAll(List<A> list)
    {
        foreach (A a in list)
        {
              Console.WriteLine("Saved Id = {0} Name = {1} City={2}", 
                  a.Id, a.Name, a.City);
        }
    }

}

AND

public class RepB
    {
        public static List<B> GetAll()
        {
            List<B> list = new List<B>();

            B b1 = new B() {Id=1, Nom="Second A", Ville="Montreal"};
            B b2 = new B() {Id=2, Nom="Second B", Ville="Paris"};
            B b3 = new B() {Id=3, Nom="Second C", Ville="New Orleans"};

            list.Add(b1);
            list.Add(b2);
            list.Add(b3);
            return list;
        }

    public static void SaveAll(List<B> list)
    {
        foreach (B b in list)
        {
            Console.WriteLine("Saved Id = {0} Name = {1} City={2}", b.Id, 
                    b.Nom, b.Ville);
        }
    }

}

How would I go about making anonymous call to my repository without having to resort to this, because in my real world example, i have 100 repositories, and not 2.

void Main()
{
    ChosenType chosentype    = RandomChosenType(); //A or B
    switch (chosentype)
    {
        case ChosenType.A:
            var listA = RepA.GetAll();
            RepA.SaveAll(listA);
            break;
        case ChosenType.B:
            var listB = RepB.GetAll();
            RepB.SaveAll(listB);
            break;
            default:
            break;
    }
}
like image 977
SerenityNow Avatar asked Aug 09 '13 12:08

SerenityNow


2 Answers

Make a base class or use an interface:

public interface IBase<T>
{
     List<T> GetAll();
     void SaveAll(List<T> items);
}

public class RepA : IBase<RepA> 
{
    public List<RepA> GetAll() { return new List<RepA>(); }
    public void SaveAll(List<RepA> repA) { }
}

public class RepB : IBase<RepB> 
{
    public List<RepB> GetAll() { return new List<RepB>(); }
    public void SaveAll(List<RepB> repB) { }
}

void Main() 
{
    IBase chosenType = RandomChosenType();
    var list = chosenType.GetAll();
}
like image 72
Darren Avatar answered Oct 20 '22 10:10

Darren


You should use a single generic repository. The operations should be handled by injected delegates. A repository could look like this:

public class GenericRepositoryExample
{

    public void Save<T>(IList<T> persons, SaveDelegate<T> save)
    {
        foreach (T person in persons)
        {
            Console.WriteLine(save(person));
        }
    }
}

Note that the save delegate is passed to the Save method. The SaveDelegate in your example could be declared as:

public delegate string SaveDelegate<T>(T input);

For ease, I have created a HelperClass containing the delegated functions. In real life helper classes should generally be avoided if possible.

public static class HelperClass
{
    public static string FrenchSave(B frenchInput)
    {

        string result = string.Format("ID = {0}; Name = {1}; City = {2}", frenchInput.Id, frenchInput.Nom, frenchInput.ville);
        return result;
    }

    public static string EnglishSave(A englishInput)
    {
        string result = string.Format("ID = {0}; Name = {1}; City = {2}", englishInput.Id, englishInput.name, englishInput.city);
        return result;
    }

}

To illustrate the use of this setup, I have created the following unit test:

  [Test]
    public void TestGenericRepository()
    {
        IList<A> aList = new List<A>();

        aList.Add(new A() { Id = 1, name = "George", city = "Chicago"});
        aList.Add(new A() { Id = 2, name = "Bill", city = "Toledo" });


        List<B> bList = new List<B>(); 

        bList.Add(new B() {Id= 1, Nom = "Nathalie", ville = "Paris"});
        bList.Add(new B() {Id = 2, Nom = "Michelle", ville = "Lyon"});


        GenericRepositoryExample repository = new GenericRepositoryExample();

        repository.Save<A>(aList,HelperClass.EnglishSave);

        repository.Save<B>(bList,HelperClass.FrenchSave);

    }
like image 28
Morten Avatar answered Oct 20 '22 10:10

Morten