Programming By A Tool This is my recorded stumbling through ASP.Net, Framework 3.5, C# 3.0, Ajax, Javascript, and Love. Stay, learn, nerd rage. It’s your life.



17Nov/080

Duck Typing my way to a Universal String Convert

- Sean

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;
6Nov/080

Cannot Resolve Method, Can’t Infer Return Type, and Funcs

- Sean

So ran into this today and the answer was actually a lot easier to understand than I thought it would be.

Say you want to order a list of objects by a number. Seems simple. Now if you have been paying attention you would know I like using Funcs.

  Func<SomeClass, Int32> orderByNumber =
    currentClass =>  currentClass.SomeNumber;

  anotherCollection = someCollection.OrderBy(orderByNumber);

Seems simple, but what if you wanted to use a method already defined in the class?

  private Int32 ReturnNumber(SomeClass currentClass)
  {
    return currentClass.SomeNumber;
  }

It seems like this could be the way to go, right?

  someCollection.OrderBy(ReturnNumber);

Compile and BOOOOOOM you get an error. It says it can't infer the return type of the method. Wait what? It's pretty obvious right, it's an integer. It had no problem inferring from the Func and you have to figure that the method itself is "typed" also. Well here's the problem (And you're dumb for not knowing this, but I'm not because I'm immune to dumb), ReturnNumber isn't a method, it's part of a method group. You can have a million (well maybe not that many) methods named ReturnNumber, all with different parameters. Why is this a problem? Well let's use lambda expressions:

  someCollection.OrderBy(currentClass =>  currentClass.SomeNumber);

At this point it knows two things: currentClass is a SomeClass and there is a Method that takes in a SomeClass and returns something. So with that in mind, it looks for such a method and finds the return type. This is no different with the Func since the Func is basically unique due to it being a named field. After all you can't have two fields named orderByNumber, but you can have many methods named ReturnNumber. That is where the problem is. When you use the second example:

  someCollection.OrderBy(ReturnNumber);

It can infer the SomeClass from the list and it sees the method. For there it has to find the method's return type. Wait, which method? If i Have 10 overloads, each with different return types, how does it know what type to use? Well the answers is, it doesn't. So basically you're screwed. Sucks, huh?

Side note: This works

  Func<SomeClass, Int32> orderByNumber = ReturnNumber;
24Jul/080

Yeah SessionTryParse

- Sean

So I got tired of seeing If Session["SomeKey"] != null... blah blah blah and thought it would be a semi worthwhile task to create a TryParse method because I'm bad like that. Not a Bad Enough Dude to Save the President, but bad.

 public static Boolean SessionTryParse<K&gt;(HttpSessionState session, String key, out K itemToSet) where K : class
 {
     itemToSet = null;

     if (session[key] != null)
     {
        itemToSet = session[key] as K;
     }

     return itemToSet != null;
 }

And for structures... which I have to cheat and only allow them to be nullable.

public static Boolean SessionTryParse<K>(HttpSessionState session, String key, out K? itemToSet) where K : struct
{
     itemToSet = null;

     if (session[key] != null && session[key] is K)
     {
        itemToSet = (K)session[key];
     }

     return itemToSet != null;
}

The idea is simple, pull in the Session, the needed Session key, and something to throw the value in. After that, just check to see if the Session + Key is null and if Session + Key is the same type of said something. That's how it's done Detroit greater metropolitan area style... punk.

USE THIS:

   using System;
   using System.Web.SessionState;
1Jul/080

Mulitple Constraint Generics and Test Base Classes

- Sean

This was basically an idea I had to have test classes inherit a TestBase that has a Static Create method on it. The reason for this is that I have found it easier to have a Create method that takes care of creating a temporary class of the type the test represents. Say I have a UserTest class and I need an address. Instead of creating and filling a whole address object in the UserTest, it easier to have a Create Method on the AddressTest class that gives me a premade Address object. Why would I want to redo a lot of the same code by having the create method on every class when I can have it on a base class and just have the non base classes specify how to create the object?

Is this really needed? I can't argue absolutely, but this forces a Create method to appear on any test class that inherits from TestBase and by use of Exceptions, forces the child classes to define how to create the object they represent. (As in it forces AddressTest to define how to create an Address object.) This also allows the Create method to be static and inherited. You could make it abstract, to skip the need for the two create methods(Create and CreateInstance), but that would hose the whole situation since static abstract is a no no. Static is a must for this situation.

The idea behind the code is to have a static Create method on the TestBase class that when called will create the test class type passed in through generics.

public static I Create()
 {
     I returnValue;
     J testToUse;

     testToUse = System.Activator.CreateInstance<J>();
     returnValue = testToUse.CreateInstance();

     return returnValue;
 }

Where J is the test class type to create. Once that test class is instantiated, the virtual method CreateInstance is called. This is where the test class creates the instance of the object it represents.

protected override I CreateInstance()
{
     I returnValue;

     returnValue = (I)new SimpleItem();
     returnValue.IsSimple = true;
     return returnValue;
}

Where I is the type of object it is going to create. In use it will look something like this:

  ItemBase itemToCreate;

  itemToCreate = SimpleItemTest<SimpleItem>.Create();

Now for the code:

//Some junk base items to demostrate the creating of an item with a base class
public class ItemBase 
{
}

//One item that will be created
public class SimpleItem : ItemBase
{
 public Boolean IsSimple { get; set; }
}

//The other item that can be created.
public class ComplexItem : ItemBase
{
 public Boolean IsComplex { get; set; }
 public Boolean IsNotSimple { get; set; }
}

//This test will be used to create a SimpleItem
public class SimpleItemTest<I> : TestBase<I, SimpleItemTest<I>> where I : SimpleItem
{
 protected override I CreateInstance()
 {
     I returnValue;

     returnValue = (I)new SimpleItem();
     returnValue.IsSimple = true;
     return returnValue;
 }
}

//This test will be used to create a ComplexItem
public class ComplexItemTest<I> : TestBase<I, ComplexItemTest<I>> where I : ComplexItem
{
 protected override I CreateInstance()
 {
     I returnValue;

     returnValue = (I)new ComplexItem();
     returnValue.IsComplex = true;
     returnValue.IsNotSimple = true;
     return returnValue;
 }
}

//This is the base class where the Create Method resides
public class TestBase<I, j> where I : class where J : TestBase<I, j>
{
 //This will either be overridden or throw an error.  Kind of a forced
 //abstract.  This is the method that the child test classes will use to
 //create whatever class they represent.
 protected virtual I CreateInstance()
 {
     throw new System.NotImplementedException();
 }

 //This is used to create a test class and call the CreateInstance method
 //so that this method can return the correct object.  The object type is
 //dependent on the type of test class that is being created.
 public static I Create()
 {
     I returnValue;
     J testToUse;

     testToUse = System.Activator.CreateInstance<J>();
     returnValue = testToUse.CreateInstance();

     return returnValue;
 }
}
Tagged as: , , , No Comments
   
NetDevInc.com