Reputation: 940
With the DRY principle in mind, how would you tackle almost identical methods (with different signatures) that work with an IEnumerable. I.e. one signature works with a specific type parameter. My question extends to the calling of private methods, and their multiple signatures.
I don't want to have two methods with identical logic - If something changes then I have to change both sets of logic. The calling of the private methods for example, how can I make the private method accept either type of IEnumerable
public class Person
{
public string Name {get; set;}
public string Age {get; set;}
}
public class SupremeBeing : Person
{
public string Power {get; set;}
}
public class Payroll
{
public void DoSomething(IEnumerable<Person> peopleIn)
{
// Do this with peopleIn
// Do that with peopleIn
// Call private method passing in peopleIn (which also has 2 signatures)
}
public void DoSomething(IEnumerable<SupremeBeing> peopleIn)
{
// Do this with peopleIn
// Do that with peopleIn
// Call private method passing in peopleIn (which also has 2 signatures)
}
}
Upvotes: 0
Views: 297
Reputation: 101
You could just have the Payroll class sort out the different types of Persons after it has run all the common operations and forward people to the appropriate extended methods.
interface IPerson {
string Name { get; set; }
string Age { get; set; }
}
public class Person : IPerson {
public string Name { get; set; }
public string Age { get; set; }
}
public class SupremeBeing : Person
{
public string Power { get; set; }
}
public class Payroll
{
public void DoSomething(IEnumerable<IPerson> peopleIn)
{
//..everyone does this and that
IEnumerable<Person> NormalPeople = peopleIn.OfType<Person>();
if (NormalPeople.Count() > 0) DoSomethingNormalSpecific(NormalPeople);
IEnumerable<SupremeBeing> SupremeBeings = peopleIn.OfType<SupremeBeing>();
if (SupremeBeings.Count() > 0) DoSomethingSupremeSpecific(SupremeBeings);
}
public void DoSomethingNormalSpecific(IEnumerable<Person> normalPeopleIn)
{
// just normal people
}
public void DoSomethingSupremeSpecific(IEnumerable<SupremeBeing> supremeBeingsIn)
{
// just Supreme Beings
}
}
Upvotes: 0
Reputation: 700442
The object oriented approach would be to make the classes handle their differences themselves. You can for example use virtual methods to have one implementation for each class.
When you can treat every object as a Person
object regardless of the actual type, then you only need one set of methods to handle the payroll, and you wouldn't need to call it with separate lists for each class, you can put them all in the same list and call the method.
Example:
public class Person {
public string Name {get; set;}
public string Age {get; set;}
virtual public int Salary { get { return 1000 + Age * 10; } }
override public string ToString() {
return Name + "(" + Age + ")";
}
}
public class SupremeBeing : Person {
public string Power {get; set;}
override public int Salary { get { return 5000 + Age * 7; } }
override public string ToString() {
return Power + " " + Name;
}
}
public class Payroll {
public void DoSomething(IEnumerable<Person> peopleIn) {
foreach (Person p in peopleIn) {
Console.log("{0} earns {1}", p, p.Salary);
}
}
}
Upvotes: 2
Reputation: 936
I don't understand your problem. You could create a generic method which does your generic stuff and then create a method which could be overridden for your special stuff.
Like:
class Something
{
protected virtual void DoSomethingSpecial<TYPE>(TYPE item)
{
}
public void DoSomethingy<TYPE>(IEnumerable<TYPE> items)
{
foreach(TYPE item in items)
{
// do whatever you have to do for every type
// do whatever you have to do in special
this.DoSomethingSpecial(item)
}
}
}
Code not tested just typed.
And then create one class for every special case. In these classes you just override DoSomethingSpecial for every type and you're done.
Upvotes: 0
Reputation: 28107
One option is to call the first method from the second:
public void DoSomething(IEnumerable<SupremeBeing> peopleIn)
{
this.DoSomething(peopleIn.Cast<Person>());
// do SupremeBeing specific stuff
}
Another option is to have a private method which does all the Person
stuff.
public void DoSomething(IEnumerable<SupremeBeing> peopleIn)
{
this.DoSomethingWithPersons(peopleIn);
}
public void DoSomething(IEnumerable<Person> peopleIn)
{
this.DoSomethingWithPersons(peopleIn);
}
private void DoSomethingWithPersons(IEnumerable<Person> peopleIn)
{
// do stuff
}
Subtle differences between the two options without more information it's hard to know which would be better.
Upvotes: 1
Reputation: 136124
It looks to me like what you want is more abstraction on the Payroll
Class
public abstract class PayrollBase<T> where T : Person
{
public void DoSomething(IEnumerable<T> peopleIn)
{
// Do this with peopleIn
// Do that with peopleIn
this.InternalLogic(peopleIn);
}
protected virtual InternalLogic(IEnumerable<T> peopleIn)
{
// do something super special
}
}
You would then implement this for your specific types
public PersonPayroll : PayrollBase<Person>
{
protected override InternalLogic(IEnumerable<Person> peopleIn)
{ ... }
}
public SupremeBeingPayroll : PayrollBase<SupremeBeing>
{
protected override InternalLogic(IEnumerable<SupremeBeing> peopleIn)
{ ... }
}
You would then use some form of factory class to instantiate the right "Payroll" for the list of people you're dealing with.
Upvotes: 3