Duck Typing my way to a Universal String Convert

So being the beacon of ignorance in the fog of brilliance, I had no idea what Duck Typing was. In short it’s the idea of assuming a class’s type based on the methods it holds.

Say you have 5 different classes, none of which share an inheritance tree. Now let’s say you have a method that takes in any object and uses the SeanIsAwsome method on the object. You could make sure that every object sent in has that method by using an interface that all the objects sent in share.

    public void SomeMethod(ISeanRules inParameter)

What if you want to send in a bunch of objects that don’t share the same interface/base class? Well you base it on what methods the class holds. If the class has the SeanIsAwsome method, then you call it. If not, well you could throw an exception, do nothing, go jogging, eat bacon, ect. That part is up to you.

The problem was that I wanted to create a universal convert that would take in a string and convert it to the 8 billion (ballpark figure) value types in C#. Now what I wanted to do is use the famous TryParse method so my first hope was that TryParse was a method on an interface they all shared. Yeah no. So next thought was to use the Duck Typing principle and say, “Hey jackass, you have a TryParse method? Yeah? Good. Use it.” ‘Course I had to find a way to do that. Turns out it wasn’t too bad.

public static class ConvertFromString
{
  public static T? ConvertTo<T>(this String numberToConvert) where T : struct
  {
    T? returnValue = null;

    MethodInfo neededInfo = GetCorrectMethodInfo(typeof(T));
    if (neededInfo != null && !numberToConvert.IsNullOrEmpty())
    {
      T output = default(T);
      object[] paramsArray = new object[2] { numberToConvert, output };
      returnValue = new T();

      object returnedValue = neededInfo.Invoke(returnValue.Value, paramsArray);

      if (returnedValue is Boolean && (Boolean)returnedValue)
      {
        returnValue = (T)paramsArray[1];
      }
      else
      {
        returnValue = null;
      }
    }

    return returnValue;
  }
}

A whaaaa?

Ok this might look odd, but it’s really simple. If it doesn’t look odd then chances are you’re smarter than me and you shouldn’t be here anyhow. First part is simple:

  public static T? ConvertTo<T>(this String numberToConvert) where T : struct

Due to this being a extension method (Opps forgot to tell you that part) I have to declare this static method in a static class. Basically I am taking in a string and returning a nullable version of whatever type I specific in the call.

    T? returnValue = null;

    MethodInfo neededInfo = GetCorrectMethodInfo(typeof(T));

Remember that MethodInfo method I had explained in the last post? The next part you might remember too, but I’m not betting on it.

    if (neededInfo != null && !numberToConvert.IsNullOrEmpty())
    {
      T output = default(T);
      object[] paramsArray = new object[2] { numberToConvert, output };
      returnValue = new T();

      object returnedValue = neededInfo.Invoke(returnValue.Value, paramsArray);

Ok so I have the method info, now I have to create the list of parameters to send in with the invoke. Pretty straight forward. If things went well, returnedValue should be a boolean. However, just incase:

    if (returnedValue is Boolean && (Boolean)returnedValue)
    {
      returnValue = (T)paramsArray[1];
    }
    else
    {
      returnValue = null;
    }

So if the returnValue is true and boolean, then the tryParse was successful. With that in mind, I still have to get the converted value. If it had not been successful than I am just going to return null since this is just meant for converting and not for whether or not it could be. It is just assumed that if it’s null, then it could not be converted at this time.

And now for the use:

  decimal? converted = someString.ConvertTo<decimal>()

An boom, you have a universal convert. YAY!

  using System;
  using System.Reflection;