Posted By: W3bbo | Nov 3rd @ 10:05 AM
page 1 of 1
Comments: 12 | Views: 200
W3bbo
W3bbo
The Master of Baiters

I was building a cellular automaton earlier (fireflies simulation) and I decided to use a C# enum to represent a fly's current state (Charging, Sensitive, and Flashing). This is fine.

 

However when it came to rendering the CA world I needed to map a Color instance to each state, so I created a static Dictionary<FlyState,Color> member whereby a colour could be matched to a fly's state.

 

However NProf reports that the dictionary's FindEntry call (from the indexer property) was consuming 50% of my program's CPU time (eh wtf).

 

I modified my code to use Dictionary<Int32,Color> and changed the indexer property call to cast the FlyState to int, and suddenly it dropped from 50% down to 4%.

 

I'd have thought Dictionary would call .GetHashCode on the enum directly, which (should) be identical to Int32.GetHashCode.

 

So what's going on, eh?

figuerres
figuerres
???

how did you declare the enum ??

 

if you did not use the format below  try this:

 

enum   FlyState : int {

 state =1,

state2 = 2, ...

};

 

see if that " : int " makes it different.

 

 

What IL is the compiler outputting? That might give you some clues as to why it's slowing down.

ktr
ktr
two sides to everything

You should use an array. Just make your enum values equal to the corresponding indices.

 

enum FlyState {
  State1 = 0,
  State2 = 1,
  // ...
}
// ...
var flyStateColors = new Color[Enum.GetValues(typeof(FlyState)).Length];
// or
var flyStateColors = new Color[/* hardcoded value */];
// set a value
flyStateColors[(int)FlyState.State1] = Color.FromArgb(255, 0, 0);
// get a value
var color = flyStateColors[(int)someFlyState];

 

You could even make extension methods to get/set values of a color array based on FlyState values instead of integer indices.

figuerres
figuerres
???

EEEWWW.... yuck  boxing and unboxing that much would be EVIL!!!  no wonder is goes to heck .... Expressionless

exoteric
exoteric
I : Next<I>

Nice, I was thinking the same thing. Actually, why doesn't the compiler optimize for this scenario. Well, it would have to deal with combinations, not just a simple list of enum values.

TommyCarlier
TommyCarlier
I want my scalps!

For mapping stuff like this, I sometimes use a trick I call "switch-as-a-dictionary": a function that just contains a switch-statement that works like dictionary, but a bit faster. I usually make it into an extension method, like this:

public static Color ToColor(this FlyState state)
{
  switch (state)
  {
    case FlyState.Charging: return Color.Green;
    case FlyState.Sensitive: return ...;
    case ...;
    default: return Color.White;
  }
}

Then you can just call it like this:

Color c = state.ToColor();

exoteric
exoteric
I : Next<I>

This is probably the best solution possible today. It will be better (looking) when/if C# gets extension properties.

 

I wonder a bit about the naming aspect of ToThis and ToThat, in a way it sounds a bit "transformational", vs AsColor() and AsString() where you are asking for new objects of something, where the new version is somehow related (by convention as here, or otherwise). With extension properties it would just be flyState.Color. On the other hand, maybe "To" implies a weaker relationship than "As" (weaker is better; no assumptions).

I came across the same problem when I did some XNA stuff. You can supply your dictionary with a comparer object during construction which eliminates the boxing/unboxing. Nick's blog post helped me:

 

http://nickgravelyn.com/2009/04/net-misconceptions-part-1/

TommyCarlier
TommyCarlier
I want my scalps!

I usually use “To” for conversion functions, just like ToString, or the methods in the Convert-class (ToInt32, ToDateTime, …).

exoteric
exoteric
I : Next<I>

As a convention that's good and mandated, I was just wondering if As is better than To, given a pre-convention time; I'm not sure it is though. This is called out in Eiffel and due to Eiffel's conventions, you can call this method without paranthesization because the mehod takes no arguments. Looks pretty neat in code.

 

http://www.eiffel-nice.org/standards/wip/any/ise50.html

Sven Groot
Sven Groot
My name has 9 letters. Coincidence? I think not...

I would use "As" when the result still somehow contains or refers to the original object, as with List<T>.AsReadOnly; the result there isn't a conversion, it's a wrapper of the original list.

page 1 of 1
Comments: 12 | Views: 200
Microsoft Communities