1

This is the first class:

public class TextBoxInt : TextBox
{
    public int min;
    public int max;

    public Value<int> value;

    public virtual void Update(object sender, EventArgs e)
    {
        int newValue;

        if (int.TryParse(Text, out newValue))
        {
            if (newValue < min || newValue > max)
            {
                //do thing A
            }

            value.Set(newValue);
            Text = value.Get().ToString();
        }

        else
        {
            Text = value.Get().ToString();
            Focus();
        }
    }

    public TextBoxInt(Value<int> value, int min, int max)
    {
        this.value = value;
        this.min = min;
        this.max = max;

        Text = value.Get().ToString();
        LostFocus += new EventHandler(update);
    }
}

This is the second class:

public class TextBoxFloat : TextBox
{
    public float min;
    public float max;

    public Value<float> value;

    public virtual void Update(object sender, EventArgs e)
    {
        float newValue;

        if (float.TryParse(Text, out newValue))
        {
            if (newValue < min || newValue > max)
            {
                //do thing A
            }

            value.Set(newValue);
            Text = value.Get().ToString();
        }

        else
        {
            Text = value.Get().ToString();
            Focus();
        }
    }

    public TextBoxFloat(Value<float> value, float min, float max)
    {
        this.value = value;
        this.min = min;
        this.max = max;

        Text = value.Get().ToString();

        LostFocus += new EventHandler(update);
    }
}

Also, this is the Value class :

public class Value<T>
{
    private T value;
    private List<IValueListener<T>> listeners = new List<IValueListener<T>>();

    public Value(T value)
    {
        this.value = value;
    }

    public T Get()
    {
        return value;
    }

    public void Set(T value)
    {
        this.value = value;

        foreach (IValueListener<T> listener in listeners)
        {
            listener.ValueUpdated(this);
        }
    }

    public void AddListener(IValueListener<T> listener)
    {
        listeners.Add(listener);
    }

    public void RemoveListener(IValueListener<T> listener)
    {
        listeners.Remove(listener);
    }
}

As you can see, the first two classes are basically the same class. The only difference is the type. First one is int, the other one float. It seems that I would make for nicer code if I could combine those two into a single class.

I can set min and max to be floats and just cast them to int when needed if it's an int class. I'd just make sure I pass "whole" floats when the type is int.

Is there any way I can do it without duplicating Update() method (If int do codeForInt, else if float do sameCodeButForFloat)?

Also, even if I do duplicate the code, I run into a problem with value.Set(newValue); - in one case newValue would be int, in other it would be float, and I can't cast either to T.

Also, is there a way to limit the generic type? To specify it can only be int or a float?

Should I just leave them as two classes, or is there a way to unify them?

Karlovsky120
  • 6,212
  • 8
  • 41
  • 94

3 Answers3

2

Instead of making separate classes, you could make a generic class.

public class BoundedTextBox<T> : TextBox where T : IComparable<T> ...

Declaring that T implements IComparable<T> will allow you to check if T is in bounds during your set operation.

if (newValue.CompareTo(min) <= 0 || newValue.CompareTo(max) >= 0)
{
    // do thing A
}
flakes
  • 21,558
  • 8
  • 41
  • 88
  • 1
    It still leaves me the issue of `int.TryParse(Text, out newValue)`. If I use a large if and process int and float separately, I a) am using twice as much code I'd like to b) am unable to then use value.set(newValue) since newValue would then be int or float, not a generic type. – Karlovsky120 Sep 09 '16 at 13:57
  • You can use a higher order function to cast the `string` into an `int` or `float` and keep it as a field within the `TextBox` class. This would be of type `Func`. – flakes Sep 09 '16 at 14:06
1

What about having an abstract TextBox<T> class inheriting from the TextBox class, where TextBox<T> has a new abstract string GetValue() method? You'll have TextBoxFloat class implementing GetValue() which will do the float specific logic and similarly will the TextBoxInt class. Your TextBox<T> would be something like

public abstract class TextBox<T> : TextBox
{
    public T min;
    public T max;

    public Value<T> value;

    public virtual void Update(object sender, EventArgs e)
    {
        Text = GetValue();
        Focus();
    }

    public TextBoxFloat(Value<T> value, T min, T max)
    {
        this.value = value;
        this.min = min;
        this.max = max;

        Text = value.Get().ToString();
        LostFocus += new EventHandler(update);
    }

    public abstract string GetValue();
}
ubi
  • 4,041
  • 3
  • 33
  • 50
  • While it's cleaner than the setup I have right now, it just increases number of classes from two to three, although again, it reduces the amount of reused code. Valiant effort, but not really the answer I was looking for (if there is one). – Karlovsky120 Sep 09 '16 at 14:00
0

As @flkes stated, a generic class is the way to go on this one. You could try something along these lines: (you can find a fine example Here)

    public abstract class TextBoxBase
    {
        public abstract object GetMin();
        public abstract object GetMax();
        public abstract object GetValue();
    }

    public abstract class TextBox<T> : TextBoxBase
    {
        public T min { get; set; }
        public T max { get; set; }
        public T value { get; set; }
        public virtual void SetTextBox(T mn, T mx, T val)
        {
            min = mn;
            max = mx;
            value = val;
        }
        public override object GetMin() { return min; }
        public override object GetMax() { return max; }
        public override object GetValue() { return value; }
    }

    public class TextBoxInt : TextBox<int>
    {
        public override void SetTextBox(int mn, int mx, int val)
        {
            min = mn;
            max = mx;
            value = val;
        }
    }

    public class TextBoxFloat : TextBox<float>
    {
        public override void SetTextBox(float mn, float mx, float val)
        {
            min = mn;
            max = mx;
            value = val;
        }
    }
Community
  • 1
  • 1
Innat3
  • 3,561
  • 2
  • 11
  • 29