Running with Code Like with scissors, only more dangerous

5Aug/080

Speedy C#, Part 1: Optimizing Long if-else or switch Branches

Posted by Rob

Lately I've been doing some interesting work that I've alluded to elsewhere dealing with the binary communications protocol hosted Blizzard Entertainment's Battle.net game service.  It's kind of what brought me into C# development in the first place; I walked away from it for a few years, and now I've been digging into it again.  And I've learned a few things between then and now; I've been particularly interested in looking at the under-the-hood workings of the CLR, and so I'm starting a new series on "Speedy C#".  Let me be the first to point out that optimizations have a unique way of obfuscating code; particularly in this example, if you don't explain why you're doing what you're doing, and exactly what result you expect, you could run into trouble, or worse, your colleagues may run into trouble.  So while going through this series,

A little background: the binary protocol used for Battle.net has about 80 or so message IDs, which generally have a different structure for each.  The messages don't necessarily come as a result of sending a message first, and so the general pattern is that a receive loop is in place that receives the data, parses it, and then sends events back to the client.  In fact, there are no synchronous requests defined by the protocol.

When I first started programming, I had handlers for every message ID in a switch/case branching construct:

   1: switch (packetID)
   2: {
   3:     case BncsPacketId.Null:
   4:         break;
   5:     case BncsPacketId.EnterChat:
   6:         string ecUniqueName = pck.ReadNTString();
   7:         string ecStatstring = pck.ReadNTString();
   8:         string ecAcctName = pck.ReadNTString();
   9:         EnteredChatEventArgs ecArgs = new EnteredChatEventArgs(ecUniqueName, ecStatstring, ecAcctName);
  10:         OnEnteredChat(ecArgs);
  11:         break;
  12:     // ... ad nauseum
  13: }

When I looked at this in ildasm, I noticed that it declared a max stack size of something ridiculously large (sorry I don't have a specific number - it was about 6 years ago).  I also noticed that there were a LOT of branches, but not necessarily in the order in which I had written them.  The compiler had intrinsically optimized my code to perform a binary search.  Fairly interesting, optimal speed at O(log N), and something that most of us wouldn't have thought of naturally!

When I last revisited this type of development, I broke all of my handlers out of the branching conditional, calling a separate method to handle each message.  This had a nice effect of making me not have to worry about variable name collisions like I had to in the above example, and it made the code slightly more maintainable.  It's difficult to gauge on paper whether that would have been better or worse performance; there was certainly far less stack allocation, but there was an additional (potentially virtual) method call.

The latest code incorporated into my library takes a different approach: I declare a Dictionary<BncsPacketId, ParseCallback>, populate it with default handlers, and allow existing handlers to be replaced and new ones to be added provided certain conditions are met.  This has had several benefits:

  • According to MSDN, Dictionary<TKey, TValue> approaches O(1), which is (obviously) the fastest lookup we could hope for. 
  • Adding support for new or changed messages does not require change to the code, only that a handler be updated via a method call.
  • Handlers can be switched at runtime.

In this code, a ParseCallback is a delegate that accepts information provided by the message header and the message contents themselves.  This has modified the entire parsing thread to be:

   1: private void Parse()
   2: {
   3:     try
   4:     {
   5:         while (IsConnected)
   6:         {
   7:             m_parseWait.Reset();
   8:  
   9:             while (m_packetQueue.Count == 0)
  10:             {
  11:                 m_parseWait.WaitOne();
  12:             }
  13:  
  14:             ParseData data = m_packetQueue.Dequeue();
  15:             if (m_packetToParserMap.ContainsKey(data.PacketID))
  16:             {
  17:                 m_packetToParserMap[data.PacketID](data);
  18:             }
  19:             else
  20:             {
  21:                 switch (data.PacketID)
  22:                 {
  23:                     #region SID_NULL
  24:                     case BncsPacketId.Null:
  25:                         break;
  26:                     #endregion
  27:                     default:
  28:                         Trace.WriteLine(data.PacketID, "Unhandled packet");
  29:                         if (!BattleNetClientResources.IncomingBufferPool.FreeBuffer(data.Data))
  30:                         {
  31:                             Debug.WriteLine(data.PacketID, "Incoming buffer was not freed for packet");
  32:                         }
  33:                         break;
  34:                 }
  35:             }
  36:         }
  37:     }
  38:     catch (ThreadAbortException)
  39:     {
  40:         // exit the thread gracefully.
  41:     }
  42: }

Now, obviously, this is a very domain-specific optimization that I wouldn't make unless it makes sense in the problem domain.  For mine, it does; I am writing the library so that others are able to integrate functionality without having to worry about modifying code that they maybe are not familiar with or are worried about breaking.  If you absolutely need to use this method, be sure to document why.

The "Speedy C#" Series:

Tagged as: , No Comments
1Aug/080

My C# 4.0 Wishlist Part 6: Automatic Properties for Enum Variables

Posted by Rob

OK, so I lied; I'm not stopping at 5 parts.

I've been working with enumerations frequently lately; the Battle.net chat protocol is binary and therefore the values that come over the wire have different contextual meanings based on the values that might have preceded them.  For example, a chat message event actually can have about a dozen meanings; it can be a server-broadcasted message, a message from another user, or just an announcement that a user joined the channel.  In addition to the standard values identifying things like message type, messages typically have one form or another of flags; if the event is based on a user, the flags contain information about the user's status on the server (whether the user is an administrator or has operator privileges in the channel).  Others, such as channel information updates, contain information about the chat channel itself, such as whether it is public, silent, or otherwise normal.

The Problem

Having had to deal with enumerations frequently has made me hate code like this:

   1: if (((UserFlags)e.Flags & UserFlags.ChannelOperator) == UserFlags.ChannelOperator)

Especially when working with bitwise values (enumerations decorated with the [Flags] attribute), because of the specific operator precedence constraints that C# places on the developer, this becomes annoying quickly.  So much so, that classes where I have to do that frequently end up with several TestFlag() methods, but even these are limited.  Consider code like this:

   1: bool TestFlag(UserFlags test, UserFlags reference) { ... }
   2: bool TestFlag(ChannelFlags test, ChannelFlags reference { ... }

Or this:

   1: bool TestFlag<T>(T test, T reference) {
   2:  // hard to implement since no meaningful type constraint can be placed on T
   3: }

Or this:

   1: bool TestFlag(int test, int reference) { ... }

In proposition 1 we have to implement n methods, either repeatedly or in a globally-defined, internal utility class; that stinks.  Proposition 2 is difficult to implement; we can't place a type constraint because C# doesn't allow enum type constraints, and since enums have a type constraint themselves of always being an integral value, this would be ideal; but type constraints in this case are limited to struct, which doesn't guarantee operator | or operator &.  In proposition 3, every time we want to test, we need to cast to int (or long) and lose type information.  I guess that works, but then you worry that you end up with code like this:

   1: if (TestFlag((int)e.User.Flags, (int)UserFlags.ServerAdministrator))
   2: { 
   3:     // ...
   4: } 
   5: else if (TestFlag((int)e.User.Flags, (int)UserFlags.ChannelOperator))
   6: {
   7:     // ...
   8: } // ...

No, there's a cleaner solution, and, like the compiler features added to C# 3.0, it doesn't require a new CLR: automatic properties on enumerations.

The Solution

Internally, enumerations are treated as their base numeric type by the CLR; the variable itself carries around type information, but it's not strong and can be changed by direct casting.  But the compiler always knows the type of a local variable and can apply it directly.  So, consider applying a property to an enumeration variable called IsEnumField.  Consider this [Flags] enumeration, and look at the code that uses it when using this style of coding:

   1: if (e.User.Flags.IsNone)
   2: {   } 
   3: else if (e.User.Flags.IsBlizzardRepresentative || e.User.Flags.IsBattleNetAdministrator)
   4: {   }
   5: else if (e.User.Flags.IsChannelOperator
   6: {   }
   7: else if (e.User.Flags.IsNoUDP)
   8: {   }

We can easily identify the pattern that the compiler supports; prefix "Is" to the field name and perform the underlying logic.

The great part about this solution is that the emitted code is exactly the same as what you or I would produce right now.  So the compiler can know by its clever compiler tricks to do this:

   1: if (e.User.Flags == UserFlags.None) {   }
   2: else if ((e.User.Flags & UserFlags.BlizzardRepresentative) == UserFlags.BlizzardRepresentative
   3:        || (e.User.Flags & UserFlags.BattleNetAdministrator) == UserFlags.BattleNetAdministrator) {   }
   4: else if ((e.User.Flags & UserFlags.ChannelOperator) == UserFlags.ChannelOperator) {   }
   5: else if ((e.User.Flags & UserFlags.NoUDP) == UserFlags.NoUDP) {   }

In that example, I qualified the type name UserFlags nine times.  Can you say "carpal tunnel"?

Future-Proofing

There are some considerations to make about this.  First, there are already going to be some enumerations in the wild with field names that begin with "Is," and it could very easily raise confusion if someone sees code such as user.Flags.IsIsOnline.  Fortunately, the solution is equally simple: create a decorator attribute, just like we did for extension methods:

   1: namespace System
   2: {
   3:     [AttributeUsage(AttributeTargets.Enum)]
   4:     public sealed class EnumPropertiesAttribute : Attribute { }
   5: }

Then, when you create an enumeration that you'd like to expose these style of properties, simply decorate the enumeration with this attribute.  IntelliSense knows to show the properties, the compiler knows to translate the properties, and we're in the free and clear.

Wouldn't it be great?

The C# 4.0 Wishlist series

22May/080

Breakout in Model-View-Presenter

Posted by Rob

I sat down tonight and in about three hours or so cranked out the first vestiges of something that kind of maybe resembles Breakout, only using graphics that are possibly worse than anything ever shown on Atari 2600 because well, I made them.

Thanks to Joel Neubeck for the video player, and thanks to digital blasphemy for the background (yes I know it's not a free image, I'll be sure to remove it before it goes anywhere).

I should also point out: I used some sounds from the Spacewar demo in XNA Game Studio 2.0.  Those sound AWESOME.

This app is built with a model in a separate assembly; the model portion of the project contains the mathematics, collision detection, and all the game objects on the screen.  We've got tiles, a ball, and a paddle.  I should also point out that there's a game board (that's the big black empty space on the screen).

The XNA game application, then, instantiates a GameBoard (that's the containing class that owns all of the rest of the objects) and then instantiates a GameBoardPresenter.  GameBoardPresenter is part of the game application itself, and it owns a copy of the GameBoard because it's intimately tied to its inner workings.

To keep things relatively efficient, the GameBoard class exposes all of its object lists as properties that return the lists.  This way, object references aren't duplicated (except for the references to the Lists), and we're not wasting unnecessary memory and copy operations.  (If you're not clear what I mean, here are the properties:)

   1: public Paddle Player
   2: {
   3:     get { return m_player; }
   4: }
   5:  
   6: public List<Ball> Balls
   7: {
   8:     get { return m_balls; }
   9: }
  10:  
  11: public List<Tile> Tiles
  12: {
  13:     get { return m_tiles; }
  14: }
  15:  
  16: public List<Projectile> Projectiles
  17: {
  18:     get { return m_projectiles; }
  19: }

Since the balls are the only pieces of the game that move, each call to Update() on the GameBoard instance iterates through each Ball object, moving it accordingly and handling any collisions.  When a collision is detected, it fires an event corresponding to the type of collision, which is consumed by the GameBoardPresenter.

One other advantage of separating out the presentation and the actual game logic is that I can scale the graphics size to anything I want; for instance, the video above was recorded and 960x720, but I was also able to run it at 1920x1200 without any apparent differences in visualization.  The internal game units actually default to a game board size of 4800x4800, and scaling is simply done within the GameBoardPresenter's Draw() method:

   1: public void Draw(SpriteBatch target)
   2: {
   3:     Texture2D currentTexture;
   4:     Vector2 scale = new Vector2(m_scale);
   5:     Vector2 offset = new Vector2(m_xOffset, 0);
   6:  
   7:     currentTexture = m_textures[BoardItemType.GameBoard];
   8:     target.Draw(currentTexture, offset,  null, Color.White, 0f, Vector2.Zero, scale, SpriteEffects.None, 1f);
   9:  
  10:     currentTexture = m_textures[BoardItemType.BasicTile];
  11:     foreach (Tile t in m_tiles)
  12:     {
  13:         target.Draw(currentTexture, t.Position * scale + offset, null, Color.White, 0f, Vector2.Zero, m_scale, SpriteEffects.None, 0f);
  14:     }
  15:  
  16:     currentTexture = m_textures[BoardItemType.Paddle];
  17:     target.Draw(currentTexture, m_paddle.Position * scale + offset, null, Color.White, 0f, Vector2.Zero, m_scale, SpriteEffects.None, 0f);
  18:  
  19:     currentTexture = m_textures[BoardItemType.Ball];
  20:     foreach (Ball b in m_balls)
  21:     {
  22:         target.Draw(currentTexture, b.Position * scale + offset, null, Color.White, 0f, Vector2.Zero, m_scale, SpriteEffects.None, 1f);
  23:     }
  24: }

The scale is calculated when the backbuffer is sized.

Source code for this isn't quite ready yet; there are some things that I want to refactor (for instance, I want the Model part to define input "actions" and that View/Presenter part to keymap inputs to actions). 

Tagged as: , , , No Comments
19May/080

Using C# Enumerations as LINQ-to-SQL Entity Properties

Posted by Rob

Have you ever created a database object and said "OK, this column is going to correspond to this enumeration"?  If you're obsessive like me, you might have even gone so far as to create column restrictions for the valid range of values, and created a special SQL type that doesn't really do anything except give you peace of mind.

Well, I've got about three such fields on a couple entities on a recent project.  Since I wanted those properties to go into C# enumerations, I tried the natural thing: I typed the enumeration's type name into the "Type" property.

Setting a column's Type property.

Unfortunately, doing this didn't work.  In fact, it seemed to break Visual Studio; updates stopped propagating to my LINQ-to-SQL classes, and in fact since I had done this before a single save, I didn't get any entity classes. 

It turns out that Matt Davis found the answer to the problem: qualify the enumeration's type name with the global:: namespace qualifier if it doesn't live in a namespace (for instance, code within an ASP.NET App_Code folder).

The global:: qualifier is important.

Once I added the qualifier to my type names, saving the DBML file correctly updated the LINQ-to-SQL classes, and I was off and running!

Tagged as: , , No Comments
15May/080

Adding Collision Detection

Posted by Rob

There's already rudimentary collision detection in the app, but only for the sides.  What if I wanted the balls to detect when they collide?

In the demo video you can already see the balls colliding (and, incidentally, the gravity changing from down, then left, up, right, and down again).  But how did I get there?  Wouldn't you know that XNA has a built-in structure called BoundingSphere that can handle that for you?  I defined the bounding sphere as centered around the ball's center point (which was defined by the texture's dimensions), and used the z-coordinate as 0.  Intrinsically, then, the bounding sphere acts like a bounding circle as long as everything is on the same Z-plane.

Next, I created a couple interfaces that are going to help me out.  Interfaces such as IPhysical and IPhysicalSphere -- they provide necessary information for collidable objects.  Here they are:

   1: public interface IPhysical
   2: {
   3:     Vector3 CenterOfMass
   4:     {
   5:         get;
   6:     }
   7:  
   8:     Vector3 Speed
   9:     {
  10:         get;
  11:         set;
  12:     }
  13:  
  14:     float Mass
  15:     {
  16:         get;
  17:     }
  18: }
  19:  
  20: public interface IPhysicalSphere : IPhysical
  21: {
  22:     BoundingSphere Bounds
  23:     {
  24:         get;
  25:     }
  26: }

By implementing these properties, a separate class can be constructed to perform the necessary math for bouncing balls.  When first implemented, colliding balls would simply switch speed vectors.  However, that only works if balls collide straight on (so that movement vectors would be inverse of each other).  When balls collide like this:

Amazing MS-Paint Art!

(Awesome MS-Paint artwork, huh?)

When balls collide like that, they don't simply exchange vectors.  What actually happens is that the speed vectors are changed according to the normal line between the two circles (or the normal plane between the two spheres).

I created a static class to do this work for me:

   1: public static class Collision
   2: {
   3:     public static void ApplyCollision(IPhysicalSphere sphereA, IPhysicalSphere sphereB)
   4:     {
   5:         Vector3 x = sphereB.CenterOfMass - sphereA.CenterOfMass;
   6:         x.Normalize();
   7:  
   8:         Vector3 v1 = sphereA.Speed;
   9:         float x1 = Vector3.Dot(x, v1);
  10:  
  11:         Vector3 v1x = x * x1;
  12:         Vector3 v1y = v1 - v1x;
  13:  
  14:         float m1 = sphereA.Mass;
  15:  
  16:         x = -x;
  17:         Vector3 v2 = sphereB.Speed;
  18:         float x2 = Vector3.Dot(x, v2);
  19:  
  20:         Vector3 v2x = x * x2;
  21:         Vector3 v2y = v2 - v2x;
  22:  
  23:         float m2 = sphereB.Mass;
  24:  
  25:         float combinedMass = m1 + m2;
  26:  
  27:         Vector3 newVelA = (v1x * ((m1 - m2) / combinedMass)) + (v2x * ((2f * m2) / combinedMass)) + v1y;
  28:         Vector3 newVelB = (v1x * ((2f * m1) / combinedMass)) + (v2x * ((m2 - m1) / combinedMass)) + v2y;
  29:  
  30:         sphereA.Speed = newVelA;
  31:         sphereB.Speed = newVelB;
  32:     }
  33: }

This was inspired by a blog post I found that covered it exceptionally.  I wish I could name the offer but I couldn't find the author's name!

Calling this method to adjust the speed vectors is done whenever collisions are detected.  That part is handled in the Game class during the Update method:

   1: for (int i = 0; i < m_balls.Count; i++)
   2: {
   3:     Ball b = m_balls[i];
   4:     for (int j = i + 1; j < m_balls.Count; j++)
   5:     {
   6:         Ball test = m_balls[j];
   7:         if (b.Bounds.Intersects(test.Bounds))
   8:         {
   9:             Collision.ApplyCollision(b, test);
  10:             b.Update(gameTime, GraphicsDevice.Viewport);
  11:             test.Update(gameTime, GraphicsDevice.Viewport);
  12:             b = null;
  13:             break;
  14:         }
  15:     }
  16:  
  17:     if (b != null)
  18:         b.Update(gameTime, GraphicsDevice.Viewport);
  19: }

And that's about all there is to it!  New source code is up!  Here's the next demo:

One other thing -- as a note, the red ball with the orange gradient has a mass of 8.0f; the others have a mass of 4.0f.

15May/080

My First XNA Application: The Bouncing Ball

Posted by Rob

My first application in XNA!  It's a... well, it's a ball that bounces.

It's bouncing!!

I created a new Windows XNA 2.0 application project.  I decided to abstract away a Ball object, as well as a GravitySource object.  There's a lot of cross-talk -- I'm not sure if this is good or not -- but it's happy enough for me. :-)

Gravity seems to be pretty straightforward to implement; the applied speed is going to be a vector direction with a constant speed as the magnitude.  Here's the code for the gravity source class:

   1: public class GravitySource
   2: {
   3:     private const float GRAVITY = 9.8f;
   4:  
   5:     private Vector2 m_gravitySpeed;
   6:  
   7:     public void ApplyGravity(ref Vector2 currentSpeed)
   8:     {
   9:         currentSpeed += m_gravitySpeed;
  10:     }
  11:  
  12:     public void ResetToDirection(Direction target)
  13:     {
  14:         switch (target)
  15:         {
  16:             case Direction.Up:
  17:                 m_gravitySpeed = new Vector2(0f, -GRAVITY);
  18:                 break;
  19:             case Direction.Left:
  20:                 m_gravitySpeed = new Vector2(-GRAVITY, 0f);
  21:                 break;
  22:             case Direction.Right:
  23:                 m_gravitySpeed = new Vector2(GRAVITY, 0f);
  24:                 break;
  25:             case Direction.Down:
  26:                 m_gravitySpeed = new Vector2(0f, GRAVITY);
  27:                 break;
  28:             case Direction.DownLeft:
  29:                 m_gravitySpeed = Vector2.Normalize(new Vector2(-1, 1)) * GRAVITY;
  30:                 break;
  31:             case Direction.DownRight:
  32:                 m_gravitySpeed = Vector2.Normalize(new Vector2(1, 1)) * GRAVITY;
  33:                 break;
  34:             case Direction.UpLeft:
  35:                 m_gravitySpeed = Vector2.Normalize(new Vector2(-1, -1)) * GRAVITY;
  36:                 break;
  37:             case Direction.UpRight:
  38:                 m_gravitySpeed = Vector2.Normalize(new Vector2(1, -1)) * GRAVITY;
  39:                 break;
  40:         }
  41:     }
  42: }

Note that I added a Direction enumeration to make it nice to read.

The game class has a reference to the ball object, and it handles the keyboard input to change the gravity direction all within the Update method:

   1: protected override void Update(GameTime gameTime)
   2: {
   3:     // Allows the game to exit
   4:     if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
   5:         this.Exit();
   6:  
   7:     KeyboardState keybstate = Keyboard.GetState();
   8:     if (keybstate.IsKeyDown(Keys.Down))
   9:     {
  10:         if (keybstate.IsKeyDown(Keys.Left))
  11:         {
  12:             m_grav.ResetToDirection(Direction.DownLeft);
  13:         }
  14:         else if (keybstate.IsKeyDown(Keys.Right))
  15:         {
  16:             m_grav.ResetToDirection(Direction.DownRight);
  17:         }
  18:         else
  19:         {
  20:             m_grav.ResetToDirection(Direction.Down);
  21:         }
  22:     }
  23:     else if (keybstate.IsKeyDown(Keys.Up))
  24:     {
  25:         if (keybstate.IsKeyDown(Keys.Left))
  26:         {
  27:             m_grav.ResetToDirection(Direction.UpLeft);
  28:         }
  29:         else if (keybstate.IsKeyDown(Keys.Right))
  30:         {
  31:             m_grav.ResetToDirection(Direction.UpRight);
  32:         }
  33:         else
  34:         {
  35:             m_grav.ResetToDirection(Direction.Up);
  36:         }
  37:     }
  38:     else if (keybstate.IsKeyDown(Keys.Left))
  39:     {
  40:         m_grav.ResetToDirection(Direction.Left);
  41:     }
  42:     else if (keybstate.IsKeyDown(Keys.Right))
  43:     {
  44:         m_grav.ResetToDirection(Direction.Right);
  45:     }
  46:  
  47:     m_ball.Update(gameTime, graphics.GraphicsDevice.Viewport);
  48:  
  49:     base.Update(gameTime);
  50: }

The game's drawing method is actually quite simple:

   1: protected override void Draw(GameTime gameTime)
   2: {
   3:     graphics.GraphicsDevice.Clear(Color.Black);
   4:  
   5:     spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
   6:     m_ball.Render(gameTime, spriteBatch);
   7:     spriteBatch.End();
   8:  
   9:     base.Draw(gameTime);
  10: }

And that gets implemented in the Ball class; here are the meat and potatoes:

   1: public void Render(GameTime time, SpriteBatch spriteBatch)
   2: {
   3:     spriteBatch.Draw(m_texture, m_position, Color.White);
   4: }
   5:  
   6: public void Update(GameTime time, Viewport bounds)
   7: {
   8:     m_position += m_speed * (float)time.ElapsedGameTime.TotalSeconds;
   9:  
  10:     int maxX = bounds.Width - m_texture.Width;
  11:     int maxY = bounds.Height - m_texture.Height;
  12:  
  13:     if (m_position.X > maxX)
  14:     {
  15:         m_speed.X *= -1.0f;
  16:         m_position.X = maxX;
  17:     }
  18:     else if (m_position.X < 0)
  19:     {
  20:         m_speed.X *= -1.0f;
  21:         m_position.X = 0;
  22:     }
  23:     else
  24:     {
  25:         // else we're in a freefall to the right!
  26:         m_gravity.ApplyGravity(ref m_speed);
  27:     }
  28:  
  29:     if (m_position.Y > maxY)
  30:     {
  31:         m_speed.Y *= -1.0f;
  32:         m_position.Y = maxY;
  33:     }
  34:     else if (m_position.Y < 0)
  35:     {
  36:         m_speed.Y *= -1.0f;
  37:         m_position.Y = 0;
  38:     }
  39:     else
  40:     {
  41:         // else we're in a freefall
  42:         // v(t) = at + k
  43:         // in this case a = -9.8
  44:         // Inverted because we're going down which is positive Y ;-) 
  45:         m_gravity.ApplyGravity(ref m_speed);
  46:     }
  47: }

One kind of odd part is that it's designed to be simply a perfectly elastic ball (m_speed.Y *= -1.0f) but it actually bounces higher over time.

Source code is downloadable here.  Thanks to Betsy Aoki's samples online - they were incredibly helpful!

Tagged as: , , No Comments
21Apr/080

The Difficulties of Using a Multicast Event-based API

Posted by Rob

I've made allusions to my current project several times, and while I can't discuss it with specifics, but I'm working with hardware; part of the device is an armature that extends to receive a piece of equipment from the user, and then it will once again extend to re-dispense the object at the conclusion of its task.  The armature controller hardware is strictly asynchronous, and as such, I decided initially to write it with asynchronous callbacks.  It's fairly straightfoward to have a method called "Extend" and an event called "Extended."  Once I was able to establish this API, I thought it would be fairly straightforward for the rest of the development team to move forward.

I thought incorrectly.

As .NET developers, I think we're conditioned from the time that we open the IDE to make sure that event handlers are wired up throughout the lifetime of the application.  In fact, both C# and Visual Basic make it so easy for multiple methods to handle events, that it's sometimes silly not to.  C# and Visual Basic event handling syntax is syntactical sugar of the Observer pattern.  And why shouldn't it be?  For probably 99.9% of the applications out there, it's great.

Still, the current project has me a bit miffed.

Consider that there are two instances in which the arm needs to be extended: one to accept the user's item, and the other to re-dispense it.  Dispensing the item happens automatically when the arm is flipped upside-down and then extended.  So, I can track state:

private void Arm_Extended(object sender, EventArgs e)
{
    if (receivingItem)
    {
        // wait for button press
    }
    else // if dispensing item
    {
        Arm.Retract();
    }
}

Doesn't this seem kludgy to you?  If not here, then consider that within a single class I potentially have six objects reporting asynchronous task results that may need to be handled differently depending on the state of the machine.

Unfortunately, the alternative method seems just as kludgy:

private void ArmExtendedForUserPrompt(object sender, EventArgs e)
{
    Arm.Extended -= handlerForArmExtendingForPrompt;
    Controller.PromptUserForItem();
}

private void ArmExtendedForDispensing(object sender, EventArgs e)
{
    Arm.Retracted += handlerForArmRetractAfterDispenseCompleted;
    Arm.Extended -= handlerForArmExtendedForDispensing;
    Arm.Retract();
}

The primary reason I've chosen the latter approach is that stack traces have a bit more meaning to me.  That's it.  I guess it's arguable that I don't need to manage umpteen state flags.  ( As a side note, I've just learned that the spell checker in Windows Live Writer considers "umpteen" to not be a spelling error ).  But the truth is that, state flags or function pointers, I'm still managing state.

It might have been more appropriate to handle asynchronous callbacks as parameters to functions:

public void Extend(object state, AsyncCallback callback) { ...

This is tricky, too; it means needing to manage an additional two variables per asynchronous call.  For an object that might support multiple concurrent asynchronous operations, that can become a nightmare of complexity management.

I don't have the right answer for this.  But it's definitely something to watch out for in the future.

Tagged as: , , No Comments
3Apr/080

Localizing a WPF Application with ResX Files

Posted by Rob

As I mentioned during my rant earlier this week, localization is fairly difficult with WPF.  As it stands right now, the only real tool support Microsoft offers for localization is a tool called LocBaml.exe, which they clearly mark as "not production-ready."  Samples available online describe how to utilize it, but there are significant drawbacks to its current implementation.  First, since LocBaml generates CSV files, it is difficult or impossible to localize most anything other than simple strings; images, for instance, are impossible to embed into a CSV file.  ResX, an XML-based file format, has not only been incredibly strong on this front, but in fact is an excellent choice because of its rich tool support available in the Visual Studio IDE.

I won't go into the depths of how LocBaml is used for localizing a WPF application; the linked sample on CodeProject and the MSDN site should give you a fairly strong idea of how it's implemented.  But here is a bulleted list of its major drawbacks.

Drawbacks to using LocBaml for WPF Localization:

  • Localization is done per-XAML-file and not per resource such as string or image.
  • Localized resources are not strongly-typed; rather, they are stored as MemoryStreams:
    A resource assembly loaded into Reflector
  • Only string resources can be easily localized.
  • Localization takes place out of the IDE and away from the localized task; generating the CSV file is done after the initial assembly is compiled and then the satellite assemblies are generated later.
  • Assemblies with strong name signatures may need to be delay-signed, waiting until after the resource modules have been generated.  (I'm not 100% certain about this).

Bending XAML to Your Localization Will

It turns out that XAML already has the perfect tool set for your application: Attached Properties.  By setting attached properties with specific IDs, we can generate markup that cleanly pulls in localization resources.  Here's a sample XAML file that demonstrates this approach:

   1:  <Window x:Class="LocalizationTestTake3.Window1"
   2:      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:      xmlns:loc="clr-namespace:LocalizationTestTake3"
   5:      Title="Window1" Height="300" Width="300">
   6:      <Grid>
   7:          <Button Height="45" Margin="55,82,75,0" loc:LocalizationProvider.ContentID="HelloWorld" Name="button1" VerticalAlignment="Top"></Button>
   8:          <Button Height="23" Margin="94,178,109,0" loc:LocalizationProvider.ContentID="English" Name="button2" VerticalAlignment="Top" Click="button2_Click"></Button>
   9:          <Button Height="23" Margin="94,0,109,24" loc:LocalizationProvider.ContentID="Spanish" Name="button3" VerticalAlignment="Bottom" Click="button3_Click"></Button>
  10:          <TextBox Height="23" Margin="55,14,59,0" loc:LocalizationProvider.TextID="HowAreYou" Name="textBox1" VerticalAlignment="Top" />
  11:      </Grid>
  12:  </Window>

In this example, you can see the attached properties defined by the LocalizationProvider class.  The IDs specified in the ContentID and TextID properties are actually defined within my .resx files.  The neat thing about this approach is that it includes full designer support, in both Visual Studio 2008 and Blend 2.5:

image

The application is able to switch at runtime by changing the Thread.CurrentThread.CurrentCulture property and then calling LocalizationProvider.UpdateAllControls().  Here's part of the class, and then I'll discuss it:

   1:      public static class LocalizationProvider 
   2:      {
   3:          private static List<DependencyObject> _contentObjects;
   4:   
   5:          static LocalizationProvider()
   6:          {
   7:              _contentObjects = new List<DependencyObject>();
   8:          }
   9:   
  10:          public static void UpdateAllObjects()
  11:          {
  12:              foreach (DependencyObject obj in _contentObjects)
  13:              {
  14:                  ResourceManager res = Resources.ResourceManager;
  15:                  ContentControl cctrl = obj as ContentControl;
  16:                  if (cctrl == null)
  17:                      throw new InvalidCastException(string.Format("Type '{0}' does not derive from type 'ContentControl'.", obj.GetType().FullName));
  18:   
  19:                  string key = obj.GetValue(ContentIDProperty) as string;
  20:   
  21:                  string resourceValue = res.GetString(key, CultureInfo.CurrentCulture);
  22:   
  23:                  cctrl.SetValue(ContentControl.ContentProperty, resourceValue);
  24:              }
  25:          }
  26:   
  27:          #region ContentID property
  28:          public static string GetContentID(DependencyObject obj)
  29:          {
  30:              return (string)obj.GetValue(ContentIDProperty);
  31:          }
  32:   
  33:          public static void SetContentID(DependencyObject obj, string value)
  34:          {
  35:              obj.SetValue(ContentIDProperty, value);
  36:          }
  37:   
  38:          private static void OnContentIDChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
  39:          {
  40:              if (obj == null)
  41:                  throw new ArgumentNullException("obj");
  42:   
  43:              ResourceManager res = Resources.ResourceManager;
  44:              ContentControl cctrl = obj as ContentControl;
  45:              if (cctrl == null)
  46:                  throw new InvalidCastException(string.Format("Type '{0}' does not derive from type 'ContentControl'.", obj.GetType().FullName));
  47:   
  48:   
  49:              string resourceValue = null;
  50:              try
  51:              {
  52:                  resourceValue = res.GetString(e.NewValue as string, CultureInfo.CurrentCulture);
  53:              }
  54:              catch (Exception ex) { }
  55:   
  56:              if (resourceValue != null)
  57:              {
  58:                  cctrl.SetValue(ContentControl.ContentProperty, resourceValue);
  59:                  if (!_contentObjects.Contains(obj))
  60:                      _contentObjects.Add(obj);
  61:              }
  62:   
  63:          }
  64:   
  65:          public static DependencyProperty ContentIDProperty =
  66:              DependencyProperty.RegisterAttached("ContentID", typeof(string), typeof(LocalizationProvider),
  67:              new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsArrange, new PropertyChangedCallback(OnContentIDChanged)));
  68:          #endregion
  69:      }

This part of the class tracks objects that use the ContentID attached property; this property is set on controls that use the Content property (any controls that inherit from ContentControl).  I'll explain why this is important in a little while.

First, we declare the ContentIDProperty as a DependencyProperty.  We tell the framework that it affects the arrangement of controls to which it is attached, and that it should call the method OnContentIDChanged when it is changed for a control.  That's down at the bottom.  We also then provide the methods for GetContentID and SetContentID - these are like extension methods for the specific dependency property we're creating.  (For more information about how a dependency property is created, see the related MSDN article).  The meat and potatoes of the class is in the OnContentIDChanged method - it looks at the new value, searches for a resource with the given ID, and then sets the control's Content dependency property to the value of the resource.  (Note: the current implementation also only works with strings.  However, changing the type to Object and then pulling the value out would work for other types of resources as well).  It then saves the DependencyObject to a list of controls that have been localized.

The UpdateAllControls iterates over each localized control and rebinds its value based on its type, using much the same logic as the initial method.

Caveats

There are a few difficulties introduced by using this method:

  • If you set the Content property of a control (by specifying internal text or by using the attribute markup syntax), you run the risk of overriding the attached property that we defined here.  For example, this markup:

    <Button Height="45" Margin="55,82,75,0" loc:LocalizationProvider.ContentID="HelloWorld" Name="button1" VerticalAlignment="Top">Hey there, world!</Button>

    would override the localized text.  This is because of the order the XAML parser loads and binds dependency properties -- remember that the Content property is also a dependency property.  I've tried a lot of different techniques for fixing this, but thus far can't find any.

  • It requires the xmlns: namespace declaration in each XAML file in which it's used.
  • Different controls and different dependency properties require different localization ID properties.  For example, TextBlocks and Runs, which have a Text property but not a Content property, need to use a different localization handler.  That involves changing the UpdateAllControls method to account for new dependency property callback types as well.
  • For very large applications, updating all controls may take longer.
  • The Text property, which is not defined on a common base class, uses reflection to set the dependency property.  The way that the set method is invoked is slower than calling the method or property setter directly.
  • Because ResX files are bound per-assembly, it can be difficult to centralize the LocalizationProvider class.  However, if it is included as an internal class in each assembly in which it is used, it can be worked around.  Another option is to use base classes, although since it's a static class, this could create a more difficult implementation.

Conclusion

For all of the potential difficulties, we like this approach better for a number of reasons:

  • It provides designer support.  You can even set the dependency properties in Blend.
  • It has richer tool support and an established file format.
    • Existing localization investments don't go away.
  • It doesn't rely on binding syntax.
    • Binding syntax is fine, and is described in the CodeProject article linked above as a convenient way to use ResX files.  However, they require editing in XAML directly; this does not.
  • It allows the runtime, dynamic modification of the UI culture.

I'll be posting a more complete sample project soon, so if this interests you, stay tuned!

14Feb/080

Comment Responses: C# 3.0 Best Practices

Posted by Rob

I've received some comments and composed some responses, included below:

First Comment/Question:

I've got questions about performance in LINQ and LINQ to SQL. 
Is it more effective to create a query against the context or against a collection on another object?  For example, which is better:

     = from t in db.Things
        where t.Something = "MyVal"
        && t.ForeignKeyId = 28

or is it better to do this:

     = from t in db.ForeignKeys
        where t.Something = "MyVal"

?  In the former, I'm running against the data context, in the latter, the (kinda) array of foreign key matches

Is it more effective to select the object or a property in the object if I am using an agregate function?  For example:

    = ( from t in db.Things select t ).Count()

or is it better to do this:

    = ( from t in db.Things select t.ThingId ).Count()

?  In the former, I select the entire t but do nothing.  Does it actually query the data, or just a place-holder?  In the latter, I've got a specific property, which I still don't need.

My answer:

I'm going to preface this by saying - as far as LINQ goes, there's SO MUCH in the toolset, and I can't claim to be much more than a novice.  What I can say about it, though, is that I can make some educated guesses about how LINQ will behave vs. LINQ-to-SQL.

In your first example, with the query against the database, looking at the "where t.Something == "MyVal" && t.ForeignKeyId == 28" (you're using double-equals-signs in those, right? ;-) ), you're probably better-off doing the complete query inside of the where clause.  Especially in LINQ-to-SQL, where that where clause is going to end up in a SQL statement anyway, you're going to be pulling against a database column, which should be fairly fast.  The only performance tweak I could suggest in this instance is ordering the foreign key ID comparison first, to avoid the char-by-char comparison of a string compare if the foreign key IDs don't match up.  This is kind of a difficult choice to make, as it might sacrifice a magnitude of code readability ("Why is Rob checking a group of values for their foreign key ID?"). 

In your second question related to the Count() aggregate, your LINQ-to-SQL and LINQ-to-Objects queries will (I believe) have similar performance characteristics, but for different reasons.

If you're using LINQ-to-SQL, the entire query should be ported to SQL and should end up reading like:

SELECT COUNT(*) FROM db.Things;

The alternative (in the alternative case you suggested) would be:

SELECT COUNT(ThingId) FROM db.Things;

I don't recall if COUNT counts NULL rows, and so you have a potential for actual incorrect data if you use the latter, though if you're sure to go against something like the PK column you're probably allright.

In any case, I don't believe it really matters.  When using LINQ-to-SQL, you'll pull from the DB.  I just pulled up a SQL Profiler, ran a query from LINQ, and I got the results I expected:

SELECT COUNT(*) AS [value] FROM [Events].[Events] AS [t0]

So it looks like we're good.  Unfortunately this query can't be visualized like non-aggregate queries:

var result = (from ev in context.Events select ev).Count();

Hovering over "result" just results in a 0 being displayed.

As for LINQ-to-Objects, my personal opinion is to use the first syntax (select t) as opposed to creating a new anonymous type.  The reason for this is that a new series of objects needs to be created, even if it just contains your one property. 

One of the things we're doing in 3.5 is to extend our existing object model, which generally shields us from database-specific implementation code, to support objects like data contexts.  However, any code generated by LINQ-to-SQL will ONLY be in our provider-specific implementation libraries that are dynamically bound at runtime.  This allows us to program with LINQ-to-SQL when we want to, but it requires that we map .NET Entity objects to our custom entity objects.  Still, this is sometimes beneficial.

Second Comment/Question:

I don't understand this discussion on Object Initializers:

"Always validate input to properties; an exception raised while setting a property will cause a memory leak, even inside try/catch

The object will already be allocated if an exception is raised within a property"

I am not sure how to express what it is that I do not understand, so maybe you can just talk to this a little bit. Typically, I would not validate parameters in an object initializer scenerio (unless they came from an external source, of course, such as user input). For example, if I pull data out of a database (my database) and build an object from it, I would not validate the data first - an exception seems correct in this case (corrupt database data). I also would not fear "memory leaks" because I assume that my "partially-constructed" object would be garbage collected like any properly-constructed object would.

In other words, I image that using object initializers is *equivalent* to (a) creating an object using the default contructor, followed by (b) setting properties. If an exception occurred setting properties - so what? [At least from "memory leak" point of view.]

My answer:

If you're populating from a database, your assumption is that the input is going to be valid, and that's certainly a valid point.  That you're thinking about this is really what I was after.

The "memory leak" I'm referring to is, again, a potential non-issue as you pointed out (the stranded object will indeed get garbage-collected).  The problem is, for me anyway, that we have no idea and no control over *when* that object gets garbage-collected, or how.  In fact, because it's implicitly compiler-created, we have no way to do anything at all with that temporary object.

Suppose we had this code:

   1:  SomeObj blah;
   2:  try {
   3:      blah = new SomeObj() { ExceptionTest = "This text generates an exception." };
   4:  } catch { }

Even here, the "<>blah_temp01" object (or whatever it's called) is still valid on the stack, but we have no way to access it.  The benefit is that code still behaves as if it was part of a constructor, and the "blah" variable is null (which is my guess of what the developers were gunning for).  But until we run out of memory and do a GC, that memory's still there, still allocated, and possibly causing heap fragmentation.

The other difficulty we run into, and this is perhaps a cheap excuse, is that when all of the properties are set on the same line, we can't tell (at least in Visual Studio) which line is causing the exception.  We could do this:

   1:  blah = new SomeObj() {
   2:                          ExceptionTest = "This text generates an exception."
   3:                       };

But does that really gain you much over:

   1:  blah = new SomeObj();
   2:  blah.ExceptionTest = "This text generates an exception.";

Ultimately, my point is this: you can handle cleaning up, disposing, and you otherwise know that an object exists when you don't use initializers.  You don't when you don't use initializers.  Suppose I have a smart card file stream that implements IDisposable.

Stream fs = new SmartCardFileStream() { FilePath = "003F/0040", Mode = FileMode.ReadWrite };

Suppose that, for whichever reason, the file opens when you set FilePath.  But, FileMode.ReadWrite isn't supported (only read or write).  You can't programmatically close that file; you have to wait for the finalizer to be invoked.  Arguably, you should wrap that declaration within a using {} block, but that's not always feasible (e.g., when you need to deal with it across events in a Winforms app). 

The primary difference is that, when an exception is raised in a constructor, it is automatically marked for garbage collection by the CLR (except in cases of a static constructor raising a TypeInitializationException, making the whole class inaccessible for the duration).  A partially-"constructed" class that raised an exception during a property-set would be problematic in that it doesn't get that benefit - we have to rely on the garbage collector to determine that there are no outstanding references to it at the next GC pass.

Summary

I chopped off some of the thank yous/hellos/I appreciates from the e-mails, and just wanted to once again say that I appreciate the comments and feedback.  Hopefully, those of you who chose to comment weren't too thrown off by my e-mail replies; I'm not particularly a fan of starting threads and posting comments on my own blog post (although I may once I get a new blog).  Also - I'd just like to point out that these are my personal opinions and not necessarily the end-all, be-all of C#; there are certainly places to use each new feature, and my goal is to investigate how features are implemented so that we know when a situation calls for them.

12Feb/080

C# 3.0 Best Practices: Downloads

Posted by Rob

I'm publishing the PowerPoint slides and sample code from the C# 3.0 Best Practices talk I gave tonight at the Arizona .NET Users Group meeting.  Once again I'd like to thank Scott Cate for extending the opportunity to me, Lorin Thwaits for pinch-hitting for Scott, and to Hudson IT Staffing for the event sponsorship.

Please note that the code sample isn't really annotated, and was designed to generate the code in the slides and the Reflector output shown.  The theme of the presentation wasn't so much "How can we do these things the best?" but more "How is this implemented, so I can choose the best way to do something?"  So the code isn't by any means a beacon of effectiveness - it's meant to go with the slides.

I'd welcome feedback and comments, as well as suggestions for additional content.  Enjoy!