Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: C#
Say we have the following :
object[] objs = new object[3]{ "the ultimate question", 42L, 1}; 
and we want to do something to the individual objects in the array like :
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 :
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 23-Nov-11 8:05am
Mehdi Gholam233.2K
Comments
Naerling at 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 ;)
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

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:
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.
  Permalink  
v3
Comments
Naerling at 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! :)
SAKryukov at 23-Nov-11 14:48pm
   
Did you see my article (please see my solution)? More or less similar.
--SA
SAKryukov at 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 at 23-Nov-11 15:05pm
   
Dictionary Type, Action of ? won't compile
Paulo Zemek at 23-Nov-11 16:46pm
   
I just corrected that and than saw your comment... it is Action<object>
Mehdi Gholam at 24-Nov-11 1:08am
   
So in the MethodToDealWithInt32 method you would do a cast right?
Paulo Zemek at 24-Nov-11 7:12am
   
Right. In that case, it will be unboxing the value, which is fast. The problem is boxing (which allocates memory) but this happens only when storing a value type as object (like when putting it into the array).
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 3

I offer a comprehensive solution in my article "Dynamic Method Dispatcher, No more long switch statements!".
 
—SA
  Permalink  
Comments
Naerling at 23-Nov-11 14:53pm
   
Bookmarked for future reading :)
SAKryukov at 23-Nov-11 21:25pm
   
Thank you, Naerling.
--SA
Mehdi Gholam at 23-Nov-11 15:11pm
   
I'm digesting your article, let you know soon.
SAKryukov at 23-Nov-11 21:25pm
   
Bon appetite!
--SA
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

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:
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.
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 Smile | :)
  Permalink  
v4
Comments
Mehdi Gholam at 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).
Naerling at 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 ;)

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

  Print Answers RSS
0 OriginalGriff 370
1 Prakriti Goyal 177
2 Sergey Alexandrovich Kryukov 155
3 jlopez788 134
4 _Amy 110
0 OriginalGriff 6,762
1 Sergey Alexandrovich Kryukov 5,539
2 Maciej Los 3,479
3 Peter Leow 3,323
4 DamithSL 2,505


Advertise | Privacy | Mobile
Web01 | 2.8.140721.1 | Last Updated 23 Nov 2011
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100