I'm currently going through various resources and trying to learn C# OOP. I haven't gone through anything on it yet but I had a go at object vs object interaction. Unfortunately it didn't go to plan and I got slightly confused on what objects I should have been referencing. I wanted to create a simple attack method that reduced the health of another object just to get the basics of object vs object interaction down. Here's the code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication7
{
class Program
{
static void Main(string[] args)
{
Dog milo = new Dog("Sparky");
Dog ruffles = new Dog("Ruffles");
milo.Attack(ruffles);
Console.ReadLine();
}
}
class Dog
{
public string name { get; set; }
public int health = 100;
public Dog(string theName)
{
name = theName;
public void Attack(Dog theDog)
{
Console.WriteLine("{0} attacks {1}.", this.name, theDog);
LoseHealth(theDog);
}
public void LoseHealth()
{
Console.WriteLine("{0} loses health!", theDog);
theDog -= 5;
}
}
}
}
The code doesn't work at all. Any idea on what I did wrong? Thanks for any help.
The code of the dog class is a bit messed up.
The Attack and LoseHealth methods are in the constructor.
Instead of referring to the health and name you only refer to theDog.
Have a look at this
class Dog
{
public string name { get; set; }
public int health = 100;
public Dog(string theName)
{
name = theName;
}
public void Attack(Dog theDog)
{
Console.WriteLine("{0} attacks {1}.", this.name, theDog.name);
LoseHealth(theDog);
}
public void LoseHealth(Dog theDog)
{
Console.WriteLine("{0} loses health!", theDog.name);
theDog.health -= 5;
}
}
Extra OO tip:
It would make more sense to change the attack and LoseHealth methods like this:
public void Attack(Dog theDog)
{
Console.WriteLine("{0} attacks {1}.", this.name, theDog.name);
theDog.LoseHealth(5);
}
public void LoseHealth(int damage)
{
Console.WriteLine("{0} loses health!", name);
this.health -= damage;
}
You did theDog -= -5. But theDog isn't a number. You need to reference the health of the dog. You also need to pass theDog into the LoseHealth() function. Change it to this:
theDog.health -= 5;
This uses dot notation to access the health of theDog.
But also, your functions are nested in the constructor. Move Attack() and LoseHealth() so they're in the class, not in the constructor body. You should end up with something like this:
class Dog
{
public string name { get; set; }
public int health = 100;
public Dog(string theName)
{
name = theName;
}
public void Attack(Dog theDog)
{
Console.WriteLine("{0} attacks {1}.", this.name, theDog);
LoseHealth(theDog);
}
public void LoseHealth(Dog theDog)
{
Console.WriteLine("{0} loses health!", theDog);
theDog.health -= 5;
}
}
By the way, never just say "my code doesn't work". Explain how it doesn't work. Include relevant exception messages if there are any.
Related
Okay so I am working on a project that haves a abstract public abstract bool IsFull { get; } this is how the school wants me to set it up. I was trying to figure out a work around that but I can't. I have a few files not sure if I want them all to post. so in my class it is inherited from a different class. so when I initiate it from the program cs class I can't get the boolean to change with a simple IsFull = true. I tried IsFull.Equal(true); but read that just a comparison attribute. I will show my code. Remember this is 100% new to me so if you asked questions why don't i do it this way the answer is I never was taught that lol.
So is there a way I can override it within the sweettooth class?
My Ninja class
using System.Collections.Generic;
using IronNinja.Interfaces;
namespace IronNinja.Models
{
abstract class Ninja
{
protected int calorieIntake;
public List<IConsumable> ConsumptionHistory;
public Ninja()
{
calorieIntake = 0;
ConsumptionHistory = new List<IConsumable>();
}
public abstract bool IsFull { get; }
public abstract void Consume(IConsumable item);
}
}
my inherited class sweettooth
using IronNinja.Interfaces;
namespace IronNinja.Models
{
class SweetTooth : Ninja
{
public string Name;
public SweetTooth(string name)
{
Name = name;
}
public override bool IsFull { get; }
public override void Consume(IConsumable item)
{
// provide override for Consume
int sweet = 0;
if (calorieIntake >= 1500)
{
}
else
{
if (item.IsSweet)
{
sweet = 10;
}
ConsumptionHistory.Add(item);
calorieIntake += item.Calories + sweet;
}
item.GetInfo();
}
}
}
Lastly my Programs .cs file
using System;
using IronNinja.Models;
namespace IronNinja
{
class Program
{
static void Main(string[] args)
{
Buffet hungryJack = new Buffet();
SweetTooth Albert = new SweetTooth("Alby");
while (!Albert.IsFull)
{
Albert.Consume(hungryJack.Serve());
}
foreach (Food item in Albert.ConsumptionHistory)
{
Console.WriteLine(item.Name);
System.Console.WriteLine(item.GetInfo());
}
}
}
}
From my understanding, the IsFull property can simply provide the logic to return whether or not the SweetTooth is full:
public override bool IsFull => calorieIntake >= 1500;
And then in SweetTooth.Consume you would check if they are full before consuming more consumables:
public override void Consume(IConsumable item)
{
// provide override for Consume
int sweet = 0;
if (IsFull)
{
return;
}
else
{
if (item.IsSweet)
{
sweet = 10;
}
ConsumptionHistory.Add(item);
calorieIntake += item.Calories + sweet;
}
item.GetInfo();
}
You simply can't, by language design. You can't make your subclass "more permissive" than the parent class.
If you want to assign IsFull property, you have to do it into the SweetTooth class through the constructor. Generally if you set a property with private setter is because you want to manage its state internally and do not let the client code to handle it.
Then, change the SweetTooth constructor as per below:
public SweetTooth(string name, bool isFull)
{
Name = name;
IsFull = isFull;
}
The alternative is to add a private backing field, but again you can edit this only internally:
private bool _isFull;
public override bool IsFull => _isFull;
The Equal method compares two values. In your specific case you called bool.Equals(bool) overload which worked as Albert.IsFull == true
Is there a way to access all the different types of object inherited from the same class using the same reference in an object without hard-coding it?
I'm developing on unity and I want to add a module in my game that could watch any particular float in a GameObject to then change another float in another GameObject once it reaches a certain value.
As an example: A "Trigger" Object/Module which set the value of Hunger=1 in a brain Object when the value of Fullness<0.5 is reached in a stomach Object.
As I'll have a big number of possible combinations I don't want to hardcode it by creating a daughter of the Trigger Class for each of them.
My initial idea was to use pointers that would be directed to the good floats to watch/change upon initialization. But apparently, we can't use unsafe code inside iterators (IEnumerator) so I'm not sure how to poll the value of Fullness.
To give an example of what I would like :
public Class Trigger{
private float* ToPoll;
private float* ToChange;
public void SetTrigger(float* poll, float* change){
ToPoll = poll;
ToChange = change;
// the loop would be a IEnumerator, not a litteral loop
while(*ToPoll < 0.5f){
sleep(0.1)
}
*ToChange = 1f
}
}
void Main(){
Trigger trigger1, trigger2;
trigger1.SetTrigger(&Stomach.fullness, &Brain.hunger)
trigger2.SetTrigger(&Sun.activityLevel, &Earth.radiationLevel)
// ^ Literally any float from any object
}
Do you have any ideas how to or better ways to implement it?
Expanding on the answer from #kara, the following code implements independent Stomach and Brain objects, and uses Being to wire them up.
What Being knows about Stomach:
it has a NeedsFoodEvent
What Being knows about Brain
there is a OnRaiseIsHungryEvent (i.e. a "hungry" signal -- who cares where it came from)
it has a IsHungryEvent
Keep in mind that in a real implementation there would likely be other objects listening for those events. e.g. maybe you have an emotion system that would switch to "hangry" and a goal-based AI that would switch to food-seeking mode. Neither system would need to be aware of the other, but both could respond to signals from the Brain. In this trivial implementation the Being responds to the Stomach signal and both notifies and responds to the Brain.
The important take-away from this is not the specific method of raising and responding to events (in this case the default .Net mechanism) but the fact that neither object knows anything about the internals of the other (see the different implementations of HumanStomach and ZombieStomach) and instead the connection is wired up at a more appropriate level (Being in this case). Also note the reliance on interfaces, which allows us to do things like create hybrid beings (i.e. pairing a ZombieBrain with a HumanStomach).
Code was written/tested with .Net Core CLI as a console app, but it should be compatible with most any version of .Net > 3.5.
using System;
using System.Linq;
using System.Threading;
namespace so_example
{
public class Program
{
static void Main(string[] args)
{
var person1 = new Being("Human 1", new HumanBrain(), new HumanStomach());
var zombie1 = new Being("Zombie 1", new ZombieBrain(), new ZombieStomach());
var hybrid1 = new Being("Hybrid 1", new ZombieBrain(), new HumanStomach());
var hybrid2 = new Being("Hybrid 2", new HumanBrain(), new ZombieStomach());
Console.WriteLine("Hit any key to exit");
Console.ReadKey();
}
}
public class HungryEventArgs : EventArgs
{
public string Message { get; set; }
}
public interface IStomach
{
event EventHandler<HungryEventArgs> NeedsFoodEvent;
}
public class Stomach : IStomach
{
public event EventHandler<HungryEventArgs> NeedsFoodEvent;
protected virtual void OnRaiseNeedsFoodEvent(HungryEventArgs e)
{
EventHandler<HungryEventArgs> handler = NeedsFoodEvent;
if (handler != null)
{
handler(this, e);
}
}
}
public class HumanStomach : Stomach
{
private Timer _hungerTimer;
public HumanStomach()
{
_hungerTimer = new Timer(o =>
{
// only trigger if breakfast, lunch or dinner (24h notation)
if (new [] { 8, 13, 19 }.Any(t => t == DateTime.Now.Hour))
{
OnRaiseNeedsFoodEvent(new HungryEventArgs { Message = "I'm empty!" });
}
else
{
Console.WriteLine("It's not mealtime");
}
}, null, 1000, 1000);
}
}
public class ZombieStomach : Stomach
{
private Timer _hungerTimer;
public ZombieStomach()
{
_hungerTimer = new Timer(o =>
{
OnRaiseNeedsFoodEvent(new HungryEventArgs { Message = "Need brains in stomach!" });
}, null, 1000, 1000);
}
}
public interface IBrain
{
event EventHandler<HungryEventArgs> IsHungryEvent;
void OnRaiseIsHungryEvent();
}
public class Brain : IBrain
{
public event EventHandler<HungryEventArgs> IsHungryEvent;
protected string _hungryMessage;
public void OnRaiseIsHungryEvent()
{
EventHandler<HungryEventArgs> handler = IsHungryEvent;
if (handler != null)
{
var e = new HungryEventArgs
{
Message = _hungryMessage
};
handler(this, e);
}
}
}
public class HumanBrain : Brain
{
public HumanBrain()
{
_hungryMessage = "Need food!";
}
}
public class ZombieBrain : Brain
{
public ZombieBrain()
{
_hungryMessage = "Braaaaaains!";
}
}
public class Being
{
protected readonly IBrain _brain;
protected readonly IStomach _stomach;
private readonly string _name;
public Being(string name, IBrain brain, IStomach stomach)
{
_stomach = stomach;
_brain = brain;
_name = name;
_stomach.NeedsFoodEvent += (s, e) =>
{
Console.WriteLine($"{_name}: {e.Message}");
_brain.OnRaiseIsHungryEvent();
};
_brain.IsHungryEvent += (s, e) =>
{
Console.WriteLine($"{_name}: {e.Message}");
};
}
}
}
Some Notes
To provide some output, I faked things in the 2 IStomach implementations. The HumanStomach creates a timer callback in the constructor which fires every 1 second and checks if the current hour is a meal hour. If it is, it raises the NeedsFoodEvent. The ZombieStomach also uses a callback every 1 second, but it just fires the NeedsFoodEvent every time. In a real Unity implementation you'd likely trigger the even based on some event from Unity -- an action the player took, after some preset amount of time, etc.
I'm not quite sure, what you want to do, but it sounds like you want to add triggers to you objects. In my understanding a trigger should be a delegate in this case.
Here an example how to define a delegate-type and add a list of triggers to your Brain-class.
Every brain can now have different triggers. I setup two derived brains to show you how to work with it:
public class TestBrain
{
private static int NextId = 1;
public TestBrain(List<MyTrigger> triggers)
{
this.Triggers = triggers;
this.Id = NextId++;
}
public int Id { get; private set; }
public int Hunger { get; set; }
public int StomachFullness { get; set; }
public List<MyTrigger> Triggers { get; private set; }
public void FireTriggers()
{
foreach (MyTrigger t in this.Triggers)
{
t.Invoke(this);
this.StomachFullness = 100;
}
}
public delegate void MyTrigger(TestBrain b);
}
public class HumanBrain : TestBrain
{
static readonly List<MyTrigger> defaultHumanTriggers = new List<MyTrigger>()
{
b => { if (b.StomachFullness < 50) { b.Hunger = 1; Console.WriteLine("{0} is hungry..", b.Id); } }
};
public HumanBrain() : base(defaultHumanTriggers)
{
}
}
public class RobotBrain : TestBrain
{
static readonly List<MyTrigger> defaultRobotTriggers = new List<MyTrigger>()
{
b => { if (b.StomachFullness < 50) { Console.WriteLine("{0} ignores hunger only want's some oil..", b.Id); } }
};
public RobotBrain() : base(defaultRobotTriggers)
{
}
}
static void Main()
{
// Create some test-data
List<TestBrain> brains = new List<TestBrain>()
{
new HumanBrain(),
new HumanBrain(),
new RobotBrain(),
new HumanBrain(),
};
Console.WriteLine(" - - - Output our Testdata - - -");
foreach (TestBrain b in brains)
{
Console.WriteLine("Status Brain {0} - Stomachfulness: {1} Hunger: {2}", b.Id, b.StomachFullness, b.Hunger);
}
Console.WriteLine(" - - - Empty stomachs - - -");
foreach (TestBrain b in brains)
{
b.StomachFullness = 0;
}
Console.WriteLine(" - - - Fire triggers - - -");
foreach (TestBrain b in brains)
{
b.FireTriggers();
}
Console.WriteLine(" - - - Output our Testdata - - -");
foreach (TestBrain b in brains)
{
Console.WriteLine("Status Brain {0} - Stomachfulness: {1} Hunger: {2}", b.Id, b.StomachFullness, b.Hunger);
}
}
I can't figure this out. The problem is that the distance, club, cleanclub, hole, scores and par all say inaccessible due to protection level and I don't know why because I thought I did everything right.
namespace homeworkchap8
{
public class Clubs
{
protected string club;
protected string distance;
protected string cleanclub;
protected string scores;
protected string par;
protected string hole;
public string myclub
{
get { return club; }
set {club = value; }
}
public string mydistance
{
get { return distance; }
set { distance = value; }
}
public string mycleanclub
{
get { return cleanclub; }
set { cleanclub = value; }
}
public string myscore
{
get { return scores; }
set { scores = value; }
}
public string parhole
{
get { return par; }
set { par = value; }
}
public string myhole
{
get { return hole; }
set { hole = value;}
}
}
}
this is the derived class:
namespace homeworkchap8
{
public class SteelClubs : Clubs, ISwingClub
{
public void SwingClub()
{
Console.WriteLine("You hit a " + myclub + " " + mydistance);
}
public void clean()
{
if (mycleanclub != "yes")
{
Console.WriteLine("your club is dirty");
}
else
{
Console.WriteLine("your club is clean");
}
}
public void score()
{
Console.WriteLine("you are on hole " + myhole + " and you scored a " +
myscore + " on a par " + parhole);
}
}
}
This is the interface:
namespace homeworkchap8
{
public interface ISwingClub
{
void SwingClub();
void clean();
void score();
}
}
here is the main code:
namespace homeworkchap8
{
class main
{
static void Main(string[] args)
{
SteelClubs myClub = new SteelClubs();
Console.WriteLine("How far to the hole?");
myClub.distance = Console.ReadLine();
Console.WriteLine("what club are you going to hit?");
myClub.club = Console.ReadLine();
myClub.SwingClub();
SteelClubs mycleanclub = new SteelClubs();
Console.WriteLine("\nDid you clean your club after?");
mycleanclub.cleanclub = Console.ReadLine();
mycleanclub.clean();
SteelClubs myScoreonHole = new SteelClubs();
Console.WriteLine("\nWhat hole are you on?");
myScoreonHole.hole = Console.ReadLine();
Console.WriteLine("What did you score on the hole?");
myScoreonHole.scores = Console.ReadLine();
Console.WriteLine("What is the par of the hole?");
myScoreonHole.par = Console.ReadLine();
myScoreonHole.score();
Console.ReadKey();
}
}
}
In your base class Clubs the following are declared protected
club;
distance;
cleanclub;
scores;
par;
hole;
which means these can only be accessed by the class itself or any class which derives from Clubs.
In your main code, you try to access these outside of the class itself. eg:
Console.WriteLine("How far to the hole?");
myClub.distance = Console.ReadLine();
You have (somewhat correctly) provided public accessors to these variables. eg:
public string mydistance
{
get
{
return distance;
}
set
{
distance = value;
}
}
which means your main code could be changed to
Console.WriteLine("How far to the hole?");
myClub.mydistance = Console.ReadLine();
Dan, it's just you're accessing the protected field instead of properties.
See for example this line in your Main(...):
myClub.distance = Console.ReadLine();
myClub.distance is the protected field, while you wanted to set the property mydistance.
I'm just giving you some hint, I'm not going to correct your code, since this is homework! ;)
myClub.distance = Console.ReadLine();
should be
myClub.mydistance = Console.ReadLine();
use your public properties that you have defined for others as well instead of the protected field members.
In your Main method, you're trying to access, for instance, club (which is protected), when you should be accessing myclub which is the public property that you created.
You organized class interface such that public members begin with "my". Therefore you must use only those members. Instead of
myScoreonHole.hole = Console.ReadLine();
you should write
myScoreonHole.myhole = Console.ReadLine();
It's because you cannot access protected member data through its class instance.
You should correct your code as follows:
namespace homeworkchap8
{
class main
{
static void Main(string[] args)
{
SteelClubs myClub = new SteelClubs();
Console.WriteLine("How far to the hole?");
myClub.mydistance = Console.ReadLine();
Console.WriteLine("what club are you going to hit?");
myClub.myclub = Console.ReadLine();
myClub.SwingClub();
SteelClubs mycleanclub = new SteelClubs();
Console.WriteLine("\nDid you clean your club after?");
mycleanclub.mycleanclub = Console.ReadLine();
mycleanclub.clean();
SteelClubs myScoreonHole = new SteelClubs();
Console.WriteLine("\nWhat hole are you on?");
myScoreonHole.myhole = Console.ReadLine();
Console.WriteLine("What did you score on the hole?");
myScoreonHole.myscore = Console.ReadLine();
Console.WriteLine("What is the par of the hole?");
myScoreonHole.parhole = Console.ReadLine();
myScoreonHole.score();
Console.ReadKey();
}
}
}
You need to use the public properties from Main, and not try to directly change the internal variables.
The reason being you cannot access protected member data through the instance of the class.
Reason why it is not allowed is explained in this blog.
Though it is irrelevant to the case at hand, for the benefit of the next person who arrives at this article through a search engine, if the default constructor of your base class is marked as private, derived classes will incur a CS0122 diagnostic.
Instead, you must promote the private method to protected.
The protected method remains inaccessible to consumers of the derived class unless said class overrides it with a new constructor.
Any thoughts on why altitude is not 5 at the end of this program?
So I have a Penguin class deriving from Birds, and in Birds class I have a check on whether the birds is flightless, and based on that I reset the given altitude to 0 or keep the provided altitude.
Supposing penguins can fly (isFlightless=false), Penguin.ArrangeBirdInPatterns(p); should trigger the ArrangeBirdInTheSky, which it does, and then the altitude should be the one I provided (=5), not zero.
My VS crashed and I'm using online fiddlers, hard to debug.
using System;
public class Bird {
public double altitude;
public bool isFlightless;
public virtual void setLocation(double longitude, double latitude) {
}
public virtual void setAltitude(double altitude) {
this.altitude = altitude;
}
public void ArrangeBirdOnGround()
{
setAltitude(0);
}
public void ArrangeBirdInTheSky()
{
setAltitude(altitude);
}
public static void ArrangeBirdInPatterns(Bird b)
{
if(b.isFlightless)
{
b.ArrangeBirdOnGround();
}
else
{
b.ArrangeBirdInTheSky();
}
}
};
public class Penguin : Bird
{
public override void setAltitude(double altitude) {
}
}
public class Program
{
public static void Main()
{
Bird p = new Penguin();
p.setAltitude(5);
p.isFlightless = false;
Penguin.ArrangeBirdInPatterns(p);
Console.WriteLine(p.altitude); //// returns 0. why not 5
}
}
Also, why can't I call it like: ArrangeBirdInPatterns(p); if I remove static from the ArrangeBirdInPatterns definition?
You're calling Penguin's setAltitude, which does nothing.
The type of p is Bird, but the type of the value contained there is Penguin, which overrides Bird.setAltitude, so that's what gets called.
You can look into the differences between virtual, override, and new keywords for more info on the different ways to subclass.
I want to know how to pass down instances of objects without knowing the Type that they are. I'd like to know this because if I have a 100 animal types, then I don't want to have a 100 if statements or a switch. I have provided a snippet, which is an example of what I want to basically achieve. Right now it obviously doesn't work where I put the comments at.
using System.IO;
using System;
using System.Collections.Generic;
class Program
{
Dictionary<string, dynamic> myAnimals = new Dictionary<string, dynamic>();
Program(){
myAnimals.Add("Maggie", new Dog("Maggie"));
myAnimals["Maggie"].bark();
myAnimals.Add("Whiskers", new Cat("Whiskers"));
myAnimals["Whiskers"].meow();
animalClinic clinic = new animalClinic();
clinic.cureAnimal(myAnimals["Whiskers"]);
}
static void Main()
{
new Program();
}
}
class Dog{
string name;
public Dog(string n){
name = n;
}
public void bark(){
Console.WriteLine("\"Woof Woof\" - " + name);
}
}
class Cat{
string name;
public Cat(string n){
name = n;
}
public void meow(){
Console.WriteLine("\"Meow Meow\" - " + name);
}
}
class animalClinic(){
public void cureAnimal(object animal){ //This is where I need some help.
if(animal.name == "Maggie"){ //I know I can use 'animal.GetType() == ...' That isn't the point.
Console.WriteLine("We heal fine dogs!"); //The point is to access various methods within the object.
}else{//I know it kind of beats the point of Type-Safety, but this is only an example and another way to do this is perfectly fine with me.
Console.WriteLine("Eww a cat!")
}
}
}
If anyone knows an alternative solution to this, then please go ahead and share!
Thanks.
EDIT: I think you'll also need to reference the animal instead of just passing it down.
This is what polymorphism is for:
public interface IAnimal
{
string name {get;set;}
void speak();
void cure();
}
public class Dog : IAnimal
{
public Dog (string n)
{
name = n;
}
public string name {get;set;}
public void bark()
{
Console.WriteLine("\"Woof Woof\" - " + name);
}
public void speak() { bark(); }
public void cure()
{
Console.WriteLine("We heal fine dogs!");
}
}
public class Cat : IAnimal
{
public Cat(string n)
{
name = n;
}
public string name {get;set;}
public void meow()
{
Console.WriteLine("\"Meow Meow\" - " + name);
}
public void speak() { meow(); }
public void cure()
{
Console.WriteLine("Eww a cat!");
}
}
class Program
{
static Dictionary<string, IAnimal> myAnimals = new Dictionary<string, IAnimal>();
static void Main()
{
myAnimals.Add("Maggie", new Dog("Maggie"));
myAnimals["Maggie"].speak();
myAnimals.Add("Whiskers", new Cat("Whiskers"));
myAnimals["Whiskers"].speak();
animalClinic clinic = new animalClinic();
clinic.cureAnimal(myAnimals["Whiskers"]);
}
}
public class animalClinic
{
public void cureAnimal(IAnimal animal)
{
animal.cure();
}
}
Create an interface (contains definitions for a group of related functionalities that a class or a struct can implement) called IAnimal which contains a Description property which returns "We heal fine dogs!" for your Dog class etc. Each of your concrete animal classes implement this interface meaning you can just call the Description property in your cureAnimal method.
Use polymorphism.
public abstract class Animal
{
public string Name { get; set; }
public abstract void Cure();
}
public class AnimalClinic
{
public void CureAnimal(Animal animal)
{
animal.Cure();
}
}
public class Dog : Animal
{
public override void Cure()
{
Console.WriteLine("We heal fine dogs!");
}
}
If you want to define the Cure logic inside of the AnimalClinic class like you do now, you might have to perform conditional execution of some sort.
This conditional execution does not have to be as unwieldy as a massive if statement or even a switch. You can research alterantive solutions to if statements here on SO. In fact, Joel Coehoorn has supplied one.
I believe the best option here is to use the strategy design pattern. Perfectly explained here http://www.dofactory.com/net/strategy-design-pattern
An example for your case is provided by ByteBlast and Joel Coehoorn's answers