0

Consider the following extension to a WPF TextBox:

public static void Parse<T>(this TextBox textBox, Func<string, T> parser)
{
    try
    {
        T value = parser(textBox.Text);
        textBox.Text = value.ToString();
    }
    catch
    {
        textBox.Text = default(T).ToString();
    }
}

That can be used like so:

private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
    ((TextBox)sender).Parse(double.Parse);
}

My question is: can the extension method be updated/modified so that I can call ((TextBox)sender).Parse(double) instead of ((TextBox)sender).Parse(double.Parse)?


EDIT

The extension method is meant to be very easily used to make sure that the user set, for example, a double or int value inside a TextBox. The idea is to use the method like so:

private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
    ((TextBox)sender).Parse(double); // make sure the input is a double
    //or
    ((TextBox)sender).Parse(int); // make sure the input is a int
}

What goes inside the extension method doesn't really matter, as long as it works, but I want a minimalist code.

Perhaps a better name for the method would be something like ParseTo(), or better yet, Validate(), as said in the comments.

Carlos
  • 586
  • 1
  • 9
  • 19
  • Isn't that just a matter of changing parser(textBox.Text) to double.Parse(textBox.Text)? And you can lose the method parameter. – Andy Sep 13 '20 at 09:57
  • @Andy I want to use the extension method for various types, e.g., `((TextBox)sender).Parse(double)` and `((TextBox)sender).Parse(int)`. Perhaps a better syntax would be `((TextBox)sender).ParseTo(double)`. – Carlos Sep 13 '20 at 09:58
  • Im lost with something, why do you need a func, as far as i know parse only works on strings – nalnpir Sep 13 '20 at 10:03
  • @nalnpir Check my edit, perhaps it clarifies the question. – Carlos Sep 13 '20 at 10:11
  • Okay would that string need an actual convertion or just a type convertion? Because im thinking that you could use something like Convert.ChangeType(variable, type) changing the signature to this textbox, Type type – nalnpir Sep 13 '20 at 10:20
  • @nalnpir I want the `TextBox.Text` to be converted from `string` to some other type `T`. If that fails, I want the `TextBox.Text` to display the `default` value for `T`. – Carlos Sep 13 '20 at 10:23
  • *That can be used like so* - not sure I'd appreciate using a UI where some slight mistake in the 17 digits I'd just typed would cause the textbox contents to be erased.. – Caius Jard Sep 13 '20 at 10:25
  • @CaiusJard However, that's besides the point. The UI is meant for short inputs, not for 17 digit numbers. And yes, I need a `TextBox`. – Carlos Sep 13 '20 at 10:28
  • I think actually, conceptually, this question is a duplicate of https://stackoverflow.com/questions/20472792/why-does-c-sharp-not-contain-iparsablet-or-itryparsablet - you're essentially saying "I want to not have the 'method that does the parse' parameter and instead be able to make an assumption about what the parse method is called" but for that really you'd need some sort of interface that C# already implemented on T (T being e.g. double) to be able to say that T was `IParsable` so you could satisfy the compiler why you're calling `Parse` on some type T.. right? – Caius Jard Sep 13 '20 at 10:29
  • 1
    _"Perhaps a better name for the method would be something like ParseTo()."_ You are actually not really parsing an input to return the parsed result. Since you are using parsing to simply validate the input, it rather should be named `Validate`. – BionicCode Sep 13 '20 at 10:53

2 Answers2

2

Have a look at this

public static string Parse<T>(string val)
{
    try
    {
        var result = (T)Convert.ChangeType(val, typeof(T));
        return result.ToString();
    }
    catch(Exception ex)
    {
        return default(T).ToString();
    }           
}

public static void Main()
{
    Console.WriteLine(Result<int>("2"));
    Console.WriteLine(Result<double>("22f"));
}

the first result will be 2, since its actually an integer, but the second value is a float, and im trying to parse it as a double, the value will be 0. If it fails it will give you the default value of T.

nalnpir
  • 1,167
  • 6
  • 14
1

You can use the generic parameter type directly:

public static void Validate<TNumeric>(this TextBox textBox) where TNumeric : struct
{
  switch (typeof(TNumeric))
  {
    case Type doubleType when doubleType == typeof(double):
      if (!double.TryParse(textBox.Text, out _))
      {
        textBox.Text = default(TNumeric).ToString();
      } break;
    case Type int32Type when int32Type == typeof(int):
      if (!int.TryParse(textBox.Text, out _))
      {
        textBox.Text = default(TNumeric).ToString();
      } break;
    default: 
      throw new ArgumentException($"Validation of type {typeof(TNumeric)} not supported");
  }
}

Example

numericTextBox.Validate<double>();

Alternatively use specialized methods:

public static void ParseDouble(this TextBox textBox)
{
  if (!double.TryParse(textBox.Text, out _))
  {
    textBox.Text = default(double).ToString();
  }
}

public static void ParseInt32(this TextBox textBox)
{
  if (!int.TryParse(textBox.Text, out _))
  {
    textBox.Text = default(int).ToString();
  }
}
BionicCode
  • 1
  • 4
  • 28
  • 44