Click here to Skip to main content
15,881,424 members
Please Sign up or sign in to vote.
4.53/5 (8 votes)
See more:
Say we have the following :
C#
object[] objs = new object[3]{ "the ultimate question", 42L, 1}; 

and we want to do something to the individual objects in the array like :
C#
foreach (object o in objs)
{
   dosomething(o);
}

Now dosomething will only take object parameters so there is boxing going on, but we require to be able to do something based on the type of the object, so we would do something like :
C#
public void dosomething(object obj)
{ 
   // one way
   if(obj.GetType() == typeof(string))
   {
      // string specific something
   }
   // another way
   if(obj is long)
   {
      // long specific something
   }
   
}

Well it's ugly and non performant, is there a better way possible using generics etc.?
Posted
Comments
Sander Rossel 23-Nov-11 14:36pm    
Good question. I've come along such cases a couple of times where it was necessary to have a huge switch statement to test for type.
Only for work with third party tools by the way ;)
Philippe Mori 23-Sep-14 21:06pm    
Do you have to use object or you can use your own base class?

Does the dispacthing based on type is done at a single location or you have to do it over and over again?

Visitor pattern might be interesting in that case.
Mehdi Gholam 24-Sep-14 16:07pm    
Generally it's object.

Again generally the dispatch is done from one place, say a tcp handler which may accept different types of messages which have to routed to their respective handlers (handlers which can be dynamically registered).

First, as your array is already typed as object, the boxing occurs when building the array. Reading the values from the array does not do a new boxing (it can unbox it).

To test for types, it is better to use the is operator. Never compare using GetType() or GetType().Name/FullName.

But then, it is all related to the purpose.
Why are you putting all the values in an array?
If you need them in an array or list, like a generic data to be viewed by the appropriate viewer (similar to Data-Templates) then you can't avoid boxing.

If you want something to deal with datatypes and that can be configurable, you can create a Dictionary. Something like:
C#
var dictionary = new Dictionary<Type, Action<object>>();

// Then you register all the types you want like:
dictionary.Add(typeof(int), MethodToDealWithInt32);
dictionary.Add(typeof(string), MethodToDealWithString);

//Then, when you get a value, you call it like:
public void Call(object value)
{
  if (value == null)
  {
    DoNullAction();
    return;
  }

  Action<object> action = dictionary[value.GetType()];
  // this will thrown an exception if there is no action registered for the type.
  action(value);
}


With that, you can register the appropriate action for any new type. Surely you will need to do that at some time in your application, but then the caller of "Call()" does not need to have any strong reference to the code that effectively deals with the object.
 
Share this answer
 
v3
Comments
Sander Rossel 23-Nov-11 14:32pm    
Nice solution! I was thinking more of an Interface that has an Object and a DoSomething method (see my answer).
Yours seems like less work, and it's still an elegant solution.
My 5! :)
Sergey Alexandrovich Kryukov 23-Nov-11 14:48pm    
Did you see my article (please see my solution)? More or less similar.
--SA
Sergey Alexandrovich Kryukov 23-Nov-11 14:50pm    
My 5. I have a solution based on more or less similar idea, perhaps more comprehensive. Please see my article referenced in my solution.
--SA
Mehdi Gholam 23-Nov-11 15:05pm    
Dictionary Type, Action of ? won't compile
Paulo Zemek 23-Nov-11 16:46pm    
I just corrected that and than saw your comment... it is Action<object>
Depends on what you want. Using Objects to store just about anything looks like a bad idea anyway.
If you'd work with Generics you'd have something like List<Object> which yields the same result.
What you have there seems like a 'God Method[^]' that can do all sorts of different things dependent on its input.
One way perhaps is to have an Interface that has a Property Object and a Method DoSomething. That way you could write a Class and a specific DoSomething for each type.
I imagine an implementation would look something like this:
C#
public interface IDoSomethingWithObj
{
    object TheObject { get; set; }
    void DoSomething();
}

public class DoSomethingWithString : IDoSomethingWithObj
{
    object IDoSomething.TheObject { get; set; } // Test if the object is a string here, otherwise throw an Exception.
    String MyString { get; set; } // Set TheObject here. Sort of 'fakes' type safety.
    void DoSomething() { // Do something with the String. }
}

Also, possibly set the String in the Constructor (MyString isn't available in the Interface).
Now you could have a list or array of IDoSomethingWithObj.
C#
foreach (IDoSomethingWithObj obj in myList)
{ obj.DoSomething }

I guess this is one way of handling such a situation (may not be the best, but better than having to make huge switch statements I guess).
The downside is that you cannot replace the Objects with other Objects (if you wanted to) because this is more or less 'type safe' so you'd have to make sure the new Objects type matched the old.

Another Method, if you know what you want (like always a String, int, long, bool in that order) you could use a Tuple[^].
The downside here is that you have no idea what Properties like 'Item1' up to 'Item8' could possible mean.

Nice question. Interested in other solutions too :)
 
Share this answer
 
v4
Comments
Mehdi Gholam 23-Nov-11 15:09pm    
Tuple is interesting but is limited to a maximum of 8 items ( I need this for RaptorDB datarows which can easily be more than 8 columns).
Sander Rossel 23-Nov-11 15:18pm    
If that's your case my solution won't work anyway. It requires you to know your types at design time :)
Can't help you with RaptorDB, I only know the relational model ;)
I offer a comprehensive solution in my article "Dynamic Method Dispatcher, No more long switch statements!".

—SA
 
Share this answer
 
Comments
Sander Rossel 23-Nov-11 14:53pm    
Bookmarked for future reading :)
Sergey Alexandrovich Kryukov 23-Nov-11 21:25pm    
Thank you, Naerling.
--SA
Mehdi Gholam 23-Nov-11 15:11pm    
I'm digesting your article, let you know soon.
Sergey Alexandrovich Kryukov 23-Nov-11 21:25pm    
Bon appetite!
--SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900