Posted By: blowdart | Jun 25th @ 3:08 AM
page 1 of 2
Comments: 49 | Views: 1204
I thought I'd throw this up for fun.

I have an object passed as a parameter into a function. It may be of various types (all inheriting from Exception funnily enough).

I want to perform certain actions based on the actual type of that object. You cannot switch on the type of an object (for rather obvious reasons).

So how would you do it? Do you feel a massive bunch of else if utilising IS is correct? I doubt there's a right answer; I just thought it would be a fun argument, errr, discussion to throw open.
Depends on where your object/function is swimming.
If this is for a live ASP.NET application I'd think about a lookup with LINQ.
The handler pattern's good for this too:

public (static if you want) class MyClass {

delegate object Handler(Object obj);
Dictionary<Type, Handler> handlerBunch = new Dictionary<Type, Handler>();

public MyClass(){
  handlerBunch.Add(typeof(int), DoSomethingWithInt);
  handlerBunch.Add(typeof(float), DoSomethingWithFloat);
  handlerBunch.Add(typeof(DateTime), DoSomethingWithDateTime);
  handlerBunch.Add(typeof(FileStream), DoSomethingWithFileStream);
}

public object DoSomething(Object obj){
  if(!handlerBunch.ContainsKey(obj.GetType()))
    throw ArgumentException("Bad argument");
  return handlerBunch[obj.GetType()] (obj);
}

public int DoSomethingWithInt(object i){
  int arg = (int)i;
  return arg + 7;
}

public string DoSomethingWithDateTime(object i){
  DateTime arg = (DateTime)i;
  return arg.ToString();
}

public object DoSomethingWithFileStream(FileStream fs){
  fs.Close();
  return null;
}


}
By the way, if all of your objects extend from Exception, why did you say they arrive as type Object? You should always try and type things to the most specific type that encompases all of the arguments, which is Exception in this case. As a general rule (so not always) if you're dealing with things typed as object then you've done something wrong.
This is a total guess, but would Object.GetType.ToString work?

If so, you could switch on that...
You can do, but then you might as well forget about performance if you're doing that.
The best is to use the "as" keyword in this case; speaking of speed. In that case you get already the cast instance (or null) and can use that after that...

FooException fe = ex as FooException;
if (fe != null)
{
    // do something with the FooException instance...
}

If I have a certain fixed amount of type checks I'm following this pattern.
Don't do this... Name doesn't contain the namespace nor assembly. This is a really really weak thing to do.

Your program doesn't compile.  Fail.

Here's a version that does:

public class MyClass
{
    private delegate object Handler(object obj);
    private readonly Dictionary<Type, Handler> handlerBunch =
        new Dictionary<Type, Handler>();

    public MyClass()
    {
        handlerBunch.Add(typeof(int), DoSomethingWithInt);
        handlerBunch.Add(typeof(float), DoSomethingWithFloat);
        handlerBunch.Add(typeof(DateTime), DoSomethingWithDateTime);
        handlerBunch.Add(typeof(FileStream), DoSomethingWithFileStream);
    }

    public object DoSomething(object obj)
    {
        if (!handlerBunch.ContainsKey(obj.GetType()))
        {
            throw new ArgumentException("obj");
        }
        else
        {
            return handlerBunch[obj.GetType()](obj);
        }
    }

    public object DoSomethingWithInt(object arg)
    {
        return (int)arg + 7;
    }

    public object DoSomethingWithFloat(object arg)
    {
        return (float)arg;
    }

    public object DoSomethingWithDateTime(object arg)
    {
        return arg.ToString();
    }

    public object DoSomethingWithFileStream(object arg)
    {
        (arg as FileStream).Close();
        return null;
    }
}

There's probably a clever way to use a delegate instead of Dictionary.ContainsKey(Type) to enable F#/Haskell-style pattern matching.

Instead of ContainsKey followed by [ ] (which is a double lookup), you can use TryGetValue, like this:

public object DoSomething(object obj)
{
    if (obj == null) throw new ArgumentNullException("obj");
    Handler lHandler;
    if (handlerBunch.TryGetValue(obj.GetType(), out lHandler))
        return lHandler(obj);
    else throw new ArgumentException("The type of obj is not supported.", "obj");
}
A little bit of fun... yes, I know it's horribly inefficient =)

public static void Main(string[] args) {

   object obj = null;
  
   obj = "Hello World";
   // obj = 32;
   // obj = DateTime.Now;
   // uncomment the above lines to see a different output

   TypeSwitcher.Switch(obj)
    .Case<string>(x => Console.WriteLine("string: {0}", x))
    .Case<int>(x => Console.WriteLine("int: {0}", x))
    .Case<DateTime>(x => Console.WriteLine("DateTime: {0}", x))
    .Execute();
}

//...

public class TypeSwitcher
{
    private readonly object obj;
    private readonly Type type;
    private readonly Dictionary<Type, Action<object>> handlers =
        new Dictionary<Type, Action<object>>();

    private TypeSwitcher(object o) {
      obj = o;
      type = o.GetType();
    }

    public TypeSwitcher Case<T>(Action<T> handler) {
      Type t = typeof(T);
      Action<object> boxedHandler = o => handler((T)o);

      if (!handlers.ContainsKey(t))
        handlers.Add(t, boxedHandler);
      else
        handlers[t] = boxedHandler;

      return this;
    }

    public void Execute() {
      Action<object> handler;
      if (handlers.TryGetValue(type, out handler))
        handler(obj);
    }

    public static TypeSwitcher Switch(object o) {
      return new TypeSwitcher(o);
    }
}

Looks cool... but why aren't you only saving the switch that is for that given type. I mean you build up a hashtable for exactly one object, where the type is well known at the time of building the hashtable. You could make it way more efficient and only store the delegate that's appropriate for the type of the object.

Only 1 TypeSwitcher-instance is created (by the Switch-method). Each Case<T>-call adds the specified handler to the dictionary of the current instance and returns this instance.

One thing I would change: you don't have to check if the dictionary contains the type to decide whether you want to add or set the handler: handlers[t] = boxedHandler will add the item if it isn't already in the dictionary.

But: he already extracts the type from the object that's passed in the constructor. Why not use that information and only store the handler that is intended for that type? I mean why storing all the handlers in the dictionary; that doesn't make any sense to me. I mean in the end he's again using the type information to get the appropriate handler and there's no way to change the object that's passed into the constructor after the "Switcher" has been created.

I wouldn't use a hashtable here because it's complete overkill and makes the whole thing slow... We can argue on this when you use some kind of inheritance chain to apply multiple handlers when some are registered for the base classes of the type etc... but in this scenario here, dunno.
You're absolutely right. it is overkill, but I thought it would be fun =). Thanks for the tip, Tommy, I did not know that. Anyway here is a slightly more efficient version. This way you could reuse the type-switcher in other parts of your program and just call .Switch(object) when you want to perform an action corresponding to the type.

public static void Main(string[] args) {

    object obj = null;
    obj = "Hello World";
    //obj = 32;
    //obj = DateTime.Now;

    new TypeSwitcher()
      .Case<string>(x => Console.WriteLine("string: {0}", x))
      .Case<int>(x => Console.WriteLine("int: {0}", x))
      .Case<DateTime>(x => Console.WriteLine("DateTime: {0}", x))
      .Switch(obj);

    Console.ReadLine();
}

// ...

public class TypeSwitcher
  {
    private readonly Dictionary<Type, Action<object>> handlers =
        new Dictionary<Type, Action<object>>();

    public TypeSwitcher() { }

    public TypeSwitcher Case<T>(Action<T> handler) {
      Type t = typeof(T);

      Action<object> boxedHandler = o => handler((T)o);
      handlers[t] = boxedHandler;

      return this;
    }

    public void Switch(object o) {
      Type t = o.GetType();

      Action<object> handler;
      if (handlers.TryGetValue(t, out handler))
        handler(o);
    }
  }

I was too fast Sad

I read over the constructor that stores the type of the object. I should just acknowledge I'm getting too old, and that young geniuses like LG can make me look stupid Wink

I would turn it around and not keep a dictionary, but just the object. Here's an implementation that's more efficient and even skips checking once it has found a case that matches. It also doesn't need a Switch-method to execute the handler.

public class TypeSwitcher
{
    readonly object fObject;
    public TypeSwitcher(object obj)
    {
        if (obj == null) throw new ArgumentNullException("obj");
        fObject = obj;
    }
    
    protected TypeSwitcher() { }
    
    public TypeSwitcher Case<T>(Action<T> action)
    {
        if (IsMatch(typeof(T)))
        {
            if (action != null) action((T)fObject);
            return IgnoreTypeSwitcher.Instance;
        }
        else return this;
    }
    
    protected virtual bool IsMatch(Type t)
    {
        return fObject.GetType() == t;
    }
    
    class IgnoreTypeSwitcher : TypeSwitcher
    {
        IgnoreTypeSwitcher() : base () { }
        
        public static IgnoreTypeSwitcher Instance = new IgnoreTypeSwitcher();
        
        protected override bool IsMatch(Type t) { return false; }
    }
}

Use it like this:

new TypeSwitcher(obj)
    .Case<string>(x => Console.WriteLine("string: {0}", x))
    .Case<int>(x => Console.WriteLine("int: {0}", x))
    .Case<DateTime>(x => Console.WriteLine("DateTime: {0}", x));
Hahaha, Tommy that's awesome. I was just about to post the exact same thing. Great minds think alike I hear.
That's some kind of a nice implementation, very object oriented, awesome... but what about running it multiple times without having to re-create the instance over and over again...