views:

272

answers:

6

Here is my method:

private void ConvertValues()  
{  
    txtResult.Text = angles[cmbUnits1.SelectedIndex];  
    double value1 = Convert.ToDouble(txtValue1.Text);  
    double value2 = Convert.ToDouble(txtValue2.Text);  
    int unit1 = cmbUnits1.SelectedIndex;  
}

What I want the method to do is to get the selected of the ComboBoxes and test the values. But I want to know if there is an alternative to this:

if( angles[cmbUnits1.SelectedIndex].Equals("Degrees") && 
    angles[cmbUnits2.SelectedIndex].Equals("Radians")) {  
    ...  
}


By the way, I'm making a kind of unit converter so I will have sections other than angles. So I would like some enum, interface, abstract class, or class that I can implement. Maybe a class with the name Unit? So I can create new objects like Unit degrees = new Unit(Units.Angle) with Units as an enum. Or just Unit sqrMillimeters = new Unit("Area");?

+3  A: 

double UnitToFactor(string unit) { returns 1 for radians, pi/180 for degrees, etc }

then

ratio = UnitToFactor(unit1) / UnitToFactor(unit2);

and dest = src*ratio

This way, instead of N^2 if() statements, u have only N.

Pavel Radzivilovsky
+1  A: 

Is there any way you could write a switch statement instead?

switch (something)
{
  case "degrees" : do work
  ...etc
}
Jason
polymorphism is a good way also, as duffymo has suggested
Jason
Maybe, but I would have to have nestled switch statements. Not much different that an if elseif
Mohit Deshpande
+8  A: 

Sure, polymorphism. Anytime you see long switch statements or if/then/else constructs it's always possible to handle them using polymorphism and factories. In your case I'd imagine an ITemperatureConverter interface with concrete implementations for Fahrenheit, Celcius, Kelvin, and Rankine would do nicely.

UPDATE:

If you find you have this logic repeated, why not have a better abstraction for an Angle than a double?

If you're writing in an object-oriented language, it's a good idea to rise above primitives (e.g, double and, yes, string) to encapsulate behavior into objects.

I'd think about an Angle class that would hang onto the value and return it as whatever measure you wanted.

Here's one way to do it in Java. I'll leave the translation to C# and the rest for you.

package angles;

public class Angle
{
    private double value;
    private AngleUnit units;

    public Angle()
    {
        this(0.0, AngleUnit.RADIANS);
    }

    public Angle(double value)
    {
        this(value, AngleUnit.RADIANS);
    }

    public Angle(double value, AngleUnit units)
    {
        this.value = value;
        this.units = units;
    }

    public double getValue()
    {
        return value;
    }

    public AngleUnit getUnits()
    {
        return units;
    }

    public Angle convert(AngleUnit newUnits)
    {
        Angle newAngle = null;

        if (this.units.equals(newUnits))
        {
            return this;
        }

        return newAngle;
    }
}

package angles;

public interface AngleConverter
{
    Angle convert(Angle angle, AngleUnit to);
}

package angles;

public enum AngleUnit
{
    DEGREES, RADIANS, GRADIANS;
}

package angles;

import java.util.HashMap;
import java.util.Map;

public class DegreeConverter implements AngleConverter
{
    private final Map<AngleUnit, Double> factors;

    public DegreeConverter(Map<AngleUnit, Double> factors)
    {
        this.factors = new HashMap<AngleUnit, Double>();
        this.factors.put(AngleUnit.DEGREES, 1.0);
        this.factors.put(AngleUnit.RADIANS, Math.PI/180.0);
        this.factors.put(AngleUnit.GRADIANS, 100.0/90.);
    }

    public Angle convert(Angle angle, AngleUnit to)
    {
        assert angle != null && to != null;

        return new Angle(angle.getValue()*this.factors.get(to), to);
    }
}
duffymo
</sarcasm> (There, fixed that for you.)
Lucas Jones
I think the quantity is angle rather than temperature :-) but the logic is identical
peter.murray.rust
Could you post a code sample or example?
Mohit Deshpande
@peter, exactly right. I didn't read it closely enough, but the example is still pertinent. I guess I should have cited degrees, radians, gradians, minutes, etc.
duffymo
A: 

You could concatenate both strings ("DegreesRadians") and call a Method called "DegreesRadians" via Reflection:

MethodInfo theMethod = thisType.GetMethod(methodName);
theMethod.Invoke(this, parameters);

Where methodName are the concatenated strings (maybe with additional information, like "convert" + unit1 + "2" + unit2, like "convertDegrees2Radians"), and parameters is an array containing both values.

ComSubVie
+1  A: 

How about a combination of SelectedIndexChanged / SelectedValueChanged Events and some polymorphism ?

Asad Butt
A: 

this is a definite opportunity to mention the antiifcampaign.com

Bedwyr Humphreys