Running with Code Like with scissors, only more dangerous


Simplified Parameter Checking: the Contract class

Posted by Rob

One of the first things we went over in my first computer science class was the idea of preconditions and postconditions for functions: what the caller should expect will be needed before and how the results will be after the call.  We also discussed parameter validation, which I've found more and more to be important.  Parameter validation is not only important for security purposes, but helpful in debugging scenarios when you wouldn't otherwise be sure that an exception is being generated because of calling code or internal function code (such as when you attempt to reference a null parameter).

.NET has a few argument-centric exceptions (ArgumentException, ArgumentOutOfRangeException, ArgumentNullException), as well as some more specific exceptions that could be raised when appropriate (FileNotFoundException, for instance).  But it's usually somewhat cumbersome to work with them in a regular way; for each function for which you're validating parameters, you need to have code along these lines:

   1:          public static int DoCheckRevision(
   2:              string valueString,
   3:              string[] files,
   4:              int mpqNumber)
   5:          {
   6:              if (valueString == null)
   7:                  throw new ArgumentNullException("valueString", Resources.crValstringNull);
   8:              if (files == null)
   9:                  throw new ArgumentNullException("files", Resources.crFileListNull);
  10:              if (files.Length != 3)
  11:                  throw new ArgumentOutOfRangeException("files", files, Resources.crFileListInvalid);
  12:          }

(Taken from MBNCSUtil - CheckRevision.cs)

What we see here is that for three parameter checks, we've got six lines of code.  Kind of lame, if you ask me.

In recent projects, I've been adding to a new class, called Contract.  Contract is a static class that has a series of methods that do nothing but validate parameters.  This is the current function list:

  • RequireInstance(object o, string paramName): Raises ArgumentNullException if o is null.
  • RequireStringWithValue(string s, string paramName): Raises ArgumentNullException if s is null, and ArgumentOutOfRangeException if s is zero-length.
  • RequireOpenConnection(IDbConnection con, string paramName): Raises ArgumentNullException if con is null, InvalidOperationException if con.State is not ConnectionState.Open.
  • RequireBytes(byte[] buffer, string paramName, int exactCount): Raises ArgumentNullException if buffer is null, ArgumentOutOfRangeException if buffer.Length is not equal to the exactCount parameter.
  • RequireBytes(byte[] buffer, string paramName, int min, int max): Raises ArgumentNullException if buffer is null, ArgumentOutOfRangeException if buffer.Length is not between min and max.
  • Assert(bool test, string failureMessage): Raises InvalidOperationException if test is false.
  • Assert(bool test, string failureMessage, string paramName): Raises ArgumentException if test is false.
  • MaxStringLength(string s, string paramName, int maxLength): Raises ArgumentNullException if s is null, ArgumentOutOfRangeException if s is zero-length or longer than maxLength.
  • RequireType(object obj, Type type, string paramName): Raises ArgumentNullException if obj is null, InvalidCastException if obj cannot be assigned to a variable of the type specified in the type parameter.
  • RequireEnumValue(object value, Type type, string paramName): The same exceptions as RequireType, as well as ArgumentOutOfRangeException if value is not defined within the enumeration specified by the type parameter.
  • RequireEnumFlagsValue(object value, Type type, string paramName): The same exceptions as RequireEnumFlagsValue, but supports bitwise combinations of flags defined.  Somewhat slower because it uses Reflection to retrieve the enum field values.
  • MaxArrayItems(Array array, string paramName, int maxItemCount): Raises ArgumentNullException if array is null, or ArgumentOutOfRangeException if the array's length is longer than maxItemCount.

All of the method calls are flagged with [DebuggerStepThrough], [DebuggerHidden], and [Conditional("DEBUG")].  That means that parameter validation will intrinsically only happen during debug builds, and you won't see where the exceptions are actually being thrown - the debugger will stop at the call to the Contract validation call, which makes it clear why exactly the exception is being thrown. 

There is an additional caveat - as I have been working on this class, I added a private static method called ValidateContractParam.  This method behaves like Assert, but throws an InvalidProgramException.  For example, if you call Contract.RequireBytes(buffer, "buffer", 30, 20) - where max < min, an InvalidProgramException will be raised.  This exception should never be caught, because it indicates you are misusing the Contract class.

Here is example code using the Contract class for my new blogging software:

   1:          public override void SaveUserProfile(User user, Dictionary<string, string> profile, IDbConnection connection)
   2:          {
   3:              Contract.RequireInstance(user, "user");
   4:              Contract.Assert(!user.IsNew, "Cannot save a user profile for a new user.  Save the user first.", "user");
   5:              Contract.RequireInstance(profile, "profile");
   6:              Contract.RequireOpenConnection(connection, "connection");
   7:          }

In this example, it is quick and efficient to ensure that all of the state being passed into method call is exactly as it should be.

The Contract class is meant to be tailored to each program that uses it as a debugging aid.  Feel free to include it in whatever programs you want; I'm releasing it to public domain.  It can be downloaded from my web site.


The Remoting Mystery… solved!

Posted by Rob

I remarked yesterday that I was having difficulty accessing remoted objects - sometimes I would never break into the methods I was calling, and sometimes calling RemotingServices.Disconnect() would fail.  I was a bit miffed about all this, and to say the documentation was unclear about why precisely an object would intermittently just stop.  I was custom-marshaling the object upon startup of the host program; it wasn't server-activated, and shouldn't have any reason for just going away.  But the failure was intermittent; I couldn't regularly reproduce the problem, and it wasn't raising an exception - it was just returning false.

Well, I went to lunch today and left my remoting host program running.  When I got back I tried to debug the client application, and of course it failed.  When I tried to close the server application, though, I didn't get my regular InvalidOperationException (the one that I was throwing) - I got a RemotingException.  And before I quickly hit enter to close the console window, I noticed it said something about how the object no longer lived on the server and therefore couldn't be shown along the remoting channels.

It turns out that MarshalByRefObject - the class from which I'm deriving my service specification objects - this class provides a method to specify the object's lifetime called InitializeLifetimeService().  This method returns an object that implements the System.Runtime.Remoting.Lifetime.ILease interface.  By changing the InitialLeaseTime value of this object to zero, the object can last forever while marshaled.  I overrode this method in a new base class, and then derived the services from this class:

   1:  public class RemotedServiceObject : MarshalByRefObject
   2:  {
   3:      public override object InitializeLifetimeService()
   4:      {
   5:          ILease lease = (ILease)base.InitializeLifetimeService();
   6:          if (lease.CurrentState == LeaseState.Initial)
   7:          {
   8:              lease.InitialLeaseTime = TimeSpan.Zero;
   9:          }
  10:          return lease;
  11:      }
  12:  }

So great news - it worked out perfectly.  No more returning false, and no more inability to connect to the object after a while.

Finally, remoting behaves like I tell it to!

Tagged as: No Comments

The Madness of Remoting

Posted by Rob

My latest project has been pretty much my first real distributed application - it involves securely storing and encrypting credit card data in a system that makes it nigh impossible to access the information.  It's actually been really fun, delving into the depths of secure programming and trying to come up with security measures to thwart perceived avenues of attack against the system.

Part of the way that this system works is by encrypting sensitive data as soon as it arrives to the application servers.  However, to prevent recovery of the data should the application servers be compromised, we chose to use a public key infrastructure system - a server elsewhere on the network issues public/private key pairs, and only the public key is stored on the application server.  The private key never actually leaves that server, and specialized trust relationships are configured so that when decryption needs to take place, it happens on the server where the private key was stored, and data exchange requires a secure channel.

The fun part about figuring out how all of this was going to work together was determining where the system lived.  One of the kicks about the application is that the encryption keys aren't allowed to be stored in "plain text" anywhere - they themselves are encrypted, and the encryption key we use to encrypt those is absolutely forbidden from being stored - we keep it in memory throughout the lifetime of the application (it is backed up with a physical backup mechanism that involves division of responsibility).

Well, with the requirement that the key encrypting key could not just disappear, I knew that we couldn't use ASP.NET to manage it - we'd have a catastrophe in the event that the process recycled.  The obvious solution was to use a Windows Service.  But the only way for a Windows Service to communicate with the outside world (in .NET anyway) is via remoting.

I'd played with remoting a small bit in the past - an app I wrote used remoting to activate objects in another AppDomain so that I could inspect the object for supported interfaces - as far as plugin systems go, it was one of my more in-depth ones.  And I'd achieved my MCTS credential in distributed applications.  But I really had (and I still really don't have) no idea what I was headed for.

Because I need to manage object lifetime myself, I am unable to use the automatic .NET Remoting configuration scheme; I need to make sure that the server has access to certain services as soon as it starts and until it ends.  I don't have the luxury of client-activated objects, even singleton ones.  So I need to set up the remoting infrastructure myself; I defined a series of service interfaces in a DLL that will be accessible from both the client and server applications, and then implement the interfaces in the server.  Seems straightforward enough.  Internal to the server-side, I also created an IService interface that defined Start() and Stop() methods - a series of objects that I could control from within the Windows Service and also work with from a factory-style utility class.

Here's sample code for the Start and Stop methods:

   2:          public void Start()
   3:          {
   4:              m_wellKnown = RemotingServices.Marshal(this, string.Format("{0}.svc", m_config.Name), typeof(IEncryptionKeyGeneratorService));
   5:          }
   7:          public void Stop()
   8:          {
   9:              if (!RemotingServices.Disconnect(this))
  10:                  throw new InvalidOperationException("Error disconnecting this object.");
  11:              m_wellKnown = null;
  12:          }

In this example, the ObjRef specified by the m_wellKnown field is initialized by the call to RemotingServices.Marshal.  The object actually marshals itself, but limits the type hierarchy by specifying exactly which interface it is casting to.  My current class, EncryptionKeyGeneratorService, inherits MarshalByRefObject and implements IEncryptionKeyGeneratorService and IService.  IEncryptionKeyGeneratorService does not inherit from IService; otherwise I would risk allowing a cast to IService, which could compromise the integrity of the application.

The part that I don't get, and really the whole purpose of this, is to explain why the call to RemotingServices.Disconnect(this) fails.

I always look at it and wonder, "Why did I get an InvalidOperationException?"  And then I realize: it's because I threw it.

The RemotingServices class is already obscure enough in that calls to Marshal are paired with calls to Disconnect, and that calls to Connect are paired with calls to Unmarshal (but not always... or something).  What I don't understand is why Disconnect() would ever return false.  It's pretty clear: I'm telling you to stop acting as an object that can be accessed elsewhere.  You're not a two-year-old child; stop telling me no.

The really scary part is that I can close out my client application altogether and still have RemotingServices be stubborn.



My C# 4.0 Wishlist, Part 5 : The raise Keyword

Posted by Rob

One of the more obscure features of C# is the ability to specify custom overloads for adding and removing event registration similarly to properties, via the add and remove keywords.  Known as "event accessors," they implement the parts of event registration that the C# compiler normally handles.  You didn't think that that += operator was implemented on the type, did you?

   1:  class Test
   2:  {
   3:      public event EventHandler Event1;
   5:      private EventHandler ev2;
   6:      public event EventHandler Event2
   7:      {
   8:          add
   9:          {
  10:              if (ev2 != null)
  11:                  ev2 = (EventHandler)Delegate.Combine(ev2, value);
  12:              else
  13:                  ev2 = value;
  14:          }
  15:          remove
  16:          {
  17:              if (ev2 != null)
  18:                  ev2 = (EventHandler)Delegate.Remove(ev2, value);
  19:          }
  20:      }
  21:      protected virtual void OnEvent2(EventArgs e)
  22:      {
  23:          if (ev2 != null)
  24:              ev2(this, e);
  25:      }
  26:  }

This pattern is actually used extensively throughout the Windows Forms library, where controls add event handlers to base event handler collections implemented within a hashtable.  I can only surmise that this is done to prevent having dozens of event fields cluttering up the classes.

Now, if we were to compile this app and disassemble it in Reflector, we'd get a very similar picture to what we've got.  Reflector would show the compiler-generated add/remove blocks for Event1, though not when the event declaration is selected, and it also indicates that there are compiler directives that show the event accessors are synchronized.

Visual Basic .NET also supports this pattern, but adds an additional keyword: the RaiseEvent keyword:

   1:  Public Class Test
   2:      Public Event Event1 As EventHandler
   4:      Private ev2 As EventHandler
   5:      Public Custom Event Event2 As EventHandler
   6:          AddHandler(ByVal value As EventHandler)
   7:              If Not ev2 Is Nothing Then
   8:                  ev2 = CType(System.Delegate.Combine(ev2, value), EventHandler)
   9:              Else
  10:                  ev2 = value
  11:              End If
  12:          End AddHandler
  14:          RemoveHandler(ByVal value As EventHandler)
  15:              If Not ev2 Is Nothing Then
  16:                  ev2 = CType(System.Delegate.Remove(ev2, value), EventHandler)
  17:              End If
  18:          End RemoveHandler
  20:          RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs)
  21:              ev2(sender, e)
  22:          End RaiseEvent
  23:      End Event
  25:      Protected Overridable Sub OnEvent2(ByVal e As EventArgs)
  26:          If Not ev2 Is Nothing Then
  27:              RaiseEvent Event2(Me, e)
  28:          End If
  29:      End Sub
  30:  End Class

In this example, Visual Basic allows you to implement exactly how Event2 is raised.  When I look at this in Reflector to see how C# uses this, here's what I see:

Reflector view of custom VB event

Reflector gives C# the raise keyword.  Why haven't the C# language experts done so?

How would this be worthwhile?  Well, suppose that we're building an application that can have plugins.  We don't know that plugins are always going to work correctly, so when they handle an event, they may raise an exception.  The problem is, if an event is invoked and the first event handler causes an exception, none of the successive handlers will be invoked.

Arguably, the "state of the application is undefined after an exception is raised, so we should gracefully exit."  But that's not always the case!  What if the way to gracefully do this is to analyze the stack trace within the application, determine which plugin caused the exception, and unload the plugin?  We can't do any of this from C#.

Give us the raise keyword!

This is the end of my "C# 4.0 Wishlist" series.  For reference, here are the other articles:


My C# 4.0 Wishlist, Part 4 : Constant typeof() Expressions

Posted by Rob

Along with some of the hacks I introduced into ShinyDesign, there was a problem using a generic parameter as an enum - I couldn't cast it back to an integral type, even System.UInt64, because T was not guaranteed to be an integral value (yet again why we should allow a type constraint, but I digress).

In any case, there have been cases where I'd like to, for instance, switch against a Type, particularly since incorporating generics.  Consider:

   1:  switch (typeof(T).GetUnderlyingType())
   2:  {
   3:      case typeof(byte):
   4:      case typeof(sbyte):
   5:          break;
   6:      case typeof(short):
   7:      case typeof(ushort):
   8:          break;
   9:      case typeof(int):
  10:      case typeof(uint):
  11:          break;
  12:      case typeof(long):
  13:      case typeof(ulong):
  14:          break;
  15:  }

This is MUCH cleaner than the alternative, current implementation:

   1:  Type t = typeof(T).GetUnderlyingType();
   2:  if (t == typeof(byte) || t == typeof(sbyte))
   3:  { }
   4:  else if (t == typeof(short) || t == typeof(ushort))
   5:  { } 
   6:  else if (t == typeof(int) || t == typeof(uint))
   7:  { } 
   8:  else if (t == typeof(long) || t == typeof(ulong))
   9:  { }

So this is a working example of how the syntax would be cleaner by allowing us to use the typeof expression result as a constant value.  If you've never tried this, the compiler complains.  Given this code:

 155:  switch (t)
 156:  {
 157:      case typeof(int):
 158:      case typeof(uint):
 159:          break;
 160:  }

I get:

EnumTypeConverter.cs(155,21): error CS0151: A value of an integral type expected

EnumTypeConverter.cs(157,22): error CS0150: A constant value is expected

EnumTypeConverter.cs(158,22): error CS0150: A constant value is expected

I'm sure you've switched over a string, though - it's one of the nice syntactical features of C#.  You might be wondering why, if switching over a string is possible, then why not a Type?

Switching on a string doesn't switch on a string - it shoots the strings into a Dictionary<string, int>, stores the offsets, and then uses a jump table with the IL switch instruction:


Yeah, obviously there's a lot of opportunity to misuse the typeof expressions.  But there are going to be legit uses, too, and honestly - if C# can have a compiler trick for strings, it can have a compiler trick for types.  And let's be honest - typeof() expressions aren't ever going to return different values for the same app (that's why people were locking types to synchronize across an AppDomain). 

This - like the inability to constrain a type constraint to an enum - is an artificial constraint that really shouldn't be there.


ShinyDesign – a Brighter Face for the PropertyGrid

Posted by Rob

I've officially released my property grid extension project, called "ShinyDesign," under the open-source BSD-like license.  I blogged about this project just a few days ago, and I'm excited to be releasing it to the public domain.

In truth, there are some ugly hacks, and I'm sure I could have done a better job commenting on what I did.  All told, the multiple-tab hack is probably the worst.  The Windows Forms PropertyGrid does not allow you to directly add additional property tabs; rather, you add Type objects that represent the tabs.  The good news is that there's a virtual method that allows you to create the tab given the Type.  The bad news is that the PropertyGrid will block you from creating additional tabs of the same Type.  The consequent solution is that, in the PropertyGridEx control, if additional tabs are used, I dynamically define an assembly and type for each PropertyTab being created.  The type is a cleaned-up version of the tab name, and the closed types are cached (if the same property tab name is used on the same PropertyGridEx in the future).  The types are then used to close a generic ExtensionPropertyTab<T> class, and the type parameter is then ignored from there.  Oh, the things we do!

The ShinyDesign documentation is available on the web as well as a direct download.  The code is also available from my website, and details for accessing it through Subversion are also provided.

Hopefully, people find it easy to use - simply drop the PropertyGridEx control onto your form, decorate your object with a few additional attributes, and you're set.  Using the PropertyGridEx is just about as painless as a run-of-the-mill PropertyGrid.

If for some reason you are unable to change a PropertyGrid out, you can use the ShinyDesign.Design.TypeDescriptorSurrogate class.  It gives you *almost* all of the benefits of the PropertyGridEx class - the key difference being that multiple property tabs are not available in this situation.  You wrap the object being inspected in a new instance of TypeDescriptorSurrogate, and assign the surrogate object as the SelectedObject of the property grid.  The actual object is updated, just as if you were working with the PropertyGridEx.

If you plan on using this in applications, I'd appreciate a nod, or at least an e-mail letting me know that you're using it and whether you found it helpful.  The license terms stipulate that my copyright notice must appear in source code redistributions, but not in binary redistributions, with the exception of the disclaimer of warranties (which must be included in all forms in some way).  Also, if you come across a bug, please drop me an e-mail so I can roll the fix into the main source tree.

Now that it's out, I'm not sure how much extra time I'll be putting into it, but I know that there are some updates I'd like to make to it, including the ability to inspect fields, methods, and events.  If possible, I'd like the ability to as closely mirror Hawkeye as possible, except that I don't really care to write the code to inject into other processes.  (This is where the multiple-property-tab idea came from in the first place).  But at the end of the day, I see the most use in this coming out of people who want to use it for their user configuration screens - that's why I built it in the first place.


My C# 4.0 Wishlist, Part 3: The Return of Const-ness

Posted by Rob

In C++, I can decorate member functions with the const modifier, which indicates that calling the member function will not modify the internal state of the object.  Here's a sample class definition:


   1:  class CTest
   2:  {
   3:  private:
   4:      int m_nVal;
   6:  public:
   7:      CTest(void);
   8:      ~CTest(void);
   9:      int GetValue() const;
  10:      void SetValue(int value);
  11:      int Add(int value) const;
  12:  };

   1:  #include "Test.h"
   3:  CTest::CTest(void)
   4:  {
   5:  }
   7:  CTest::~CTest(void)
   8:  {
   9:  }
  11:  int CTest::Add(int value) const
  12:  {
  13:      return value + m_nVal;
  14:  }
  16:  int CTest::GetValue() const
  17:  {
  18:      return m_nVal;
  19:  }
  21:  void CTest::SetValue(int value) 
  22:  {
  23:      m_nVal = value;
  24:  }

This example demonstrates wrapping an integer value, and shows how GetValue() and Add() can be const by not modifying any internal values.  Now, if I change the Add method to a void type, and add the value to the internal state, I get a compiler error.  Here's the updated method:

   1:  void CTest::Add(int value) const
   2:  {
   3:      return SetValue(value + m_nVal);
   4:  }


error C2662: 'CTest::SetValue' : cannot convert 'this' pointer from 'const CTest' to 'CTest &'

I get a similar error (about lvalue type casting) if I just set the value within the Add method.

So how should this apply in C#?  Realistically, I think I'd like it to just apply to member functions and properties.  There are a lot of ways to use const in C and C++ - it's almost scary, actually (could you imagine using one parameter and having three const modifiers?).  In C#, I'd just like it to be part of the method contract:

   1:  public class Class1
   2:  {
   3:      private string m_firstName, m_lastName;
   4:      private int m_val;
   6:      public int Value
   7:      {
   8:          get const
   9:          {
  10:              return m_val;
  11:          }
  12:          set
  13:          {
  14:              m_val = value;
  15:          }
  16:      }
  18:      public string GetName() const
  19:      {
  20:          return string.Format("{0}, {1}", m_lastName, m_firstName);
  21:      }
  22:  }

In both of these examples, we can tell that the internal state of the object itself isn't modified (note that the const modifier only applies to the get method of the Value property).  It provides the user of the class additional information, and it helps to enforce the contract on the side of the class author.

Implementation in the compiler: add a System.Runtime.CompilerServices.ConstMethodAttribute and apply it to the methods as marked.  Add a static code analysis rule that checks to see if a method could be marked as const, and if so, flag a warning.

I don't know that there are compiler optimizations that can be made, but one way or another, I think that it's a good method with which to give additional information about method implementations.  Sometimes we don't want to call properties or methods if we know that it can cause side effects, because let's be honest: the base class library's documentation isn't always 100% clear.  That's why we need tools like .NET Reflector.  One more tool to help our code be self-documenting is one more good thing.


My C# 4.0 Wishlist, Part 1 : Eliminate Type Constraint Constraints

Posted by Rob

C# 2.0 introduced a great new feature to the .NET Type system: generics.  Generics are really cool in that they allow you to define template classes; I can use a single class definition to provide a strongly typed collection, for example.  They enable some other tricks that I would tend to consider something of a "hack" as well; for example, this expression evaluates to true:

   1:  typeof(IEnumerable<int>) != typeof(IEnumerable<double>)

This expression is nice because there are some odd class design decisions in places like the PropertyGrid's type structure.  For example, in order to add a PropertyTab to the list of the PropertyGrid's tabs, you need to add a Type to the PropertyTabCollection exposed by the PropertyGrid's PropertyTabs property.  The PropertyGrid caches the tabs that it creates, and so you can't add a single Type to create two property tabs.  Consequently, even if you override the CreateTab method, you can't expect to add two tabs with the same Type.

My solution, then, was to create ExtensionPropertyTab<T>.  This class's type parameter is utterly useless; I create an arbitrary Type using Reflection Emit, close my ExtensionPropertyTab generic type definition with it, and then add the PropertyTab with that closed type.  Works great!  This stuff will be in an upcoming blog post about my PropertyGridEx project.

All of that is leading up to my next hack and, ultimately, my wishlist item #1 for C# 4.0.

There's a simple design-time class called EnumConverter.  This class is the default type converter for all enumeration types; EnumConverter is what displays the Enum names in the property grid when you're choosing items.  I'm creating a type surrogate class that allows you to customize the names of properties, and I've also been working on displaying better values for enumerations.  To this end, I created the EnumTypeConverter<T> class - this class provides enumeration names, but also retrieves friendly names from attributes on each enum entry.  Using generics, I'm able to cache the friendly names so that reflection only needs to be invoked once; System.Enum does something similar.

What I'd like to do, however, is say this:

   1:  public class EnumTypeConverter<T> : TypeConverter where T : enum

C# doesn't allow me to do this.  I get two errors:

error CS1031: Type expected

error CS1001: Identifier expected

So I try using the type name instead:

   1:  public class EnumTypeConverter<T> : TypeConverter where T : Enum

C# doesn't like this either:

error CS0702: Constraint cannot be special class 'System.Enum'

Why?  I get the same error with System.ValueType, even though ultimately it means the same thing as "struct" (though I could understand this difference).  But I can't do this with System.Delegate either (how about calling Invoke() or BeginInvoke() on T?).

Being able to specify Enum as a base would allow me to:

  • Explicitly cast between T and integral numeric types.
  • Specify 0 as the default value of T rather than using default(T).
  • Perform bitwise operations on them

There's really no reason to have a constraint like "Constraint cannot be special class 'System.Enum'."  Let's eliminate this artificial barrier - there shouldn't be any changes needed to be made to the CLR.


My C# 4.0 Wishlist, Part 2 : Default/Optional Parameters

Posted by Rob

When I was first getting into C# (about .NET 1.0 Beta 2), I saw that it didn't support optional parameters.  The explanation was simple enough: method overloads supported an alternative method of default or optional parameters.  I thought that it was probably a useful choice.  But, check this out:

   1:  public static class MessageBox
   2:  {
   3:      static void Show(string message)
   4:      {
   5:          Show(message, null, MessageBoxButtons.OK, MessageBoxIcon.Information);
   6:      }
   8:      static void Show(string message, string title)
   9:      {
  10:          Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Information);
  11:      }
  13:      static void Show(string message, string title, MessageBoxButtons buttons, MessageBoxIcon icon)
  14:      {
  15:          // actually perform the showing
  16:      }
  18:      // and more overloads
  19:  }

This is pretty lame, isn't it?  Why can't I just do everything with a single method?

   1:  public static class MessageBox
   2:  {
   3:      static void Show(string message, string title = "", MessageBoxButtons button = MessageBoxButtons.OK, 
   4:          MessageBoxIcon icon = MessageBoxIcon.Information);
   5:  }

So, the question is, how precisely could this work?  Well, let's take a look at how this works in Visual Basic.

   1:  Public Class MessageBox
   2:      Public Shared Sub Show(ByVal message As String, Optional ByVal title As String = "", _
   3:                             Optional ByVal buttons As MessageBoxButtons = MessageBoxButtons.OK, _
   4:                             Optional ByVal icon As MessageBoxIcon = MessageBoxIcon.Information)
   5:      End Sub
   6:  End Class

Visual Basic turns this into a method and annotates the parameter list with attributes.  In C# we could express it like this:

   1:  public static class MessageBox
   2:  {
   3:      static void Show(string message, 
   4:          [Optional]
   5:          [DefaultParameterValue("")]
   6:          string title, 
   7:          [Optional]
   8:          [DefaultParameterValue(MessageBoxButtons.OK)]
   9:          MessageBoxButtons buttons, 
  10:          [Optional]
  11:          [DefaultParameterValue(MessageBoxIcon.Information)]
  12:          MessageBoxIcon icon)
  13:      {
  15:      }
  16:  }

In languages that support optional parameters, the compiler provides parameters, so that a call that leaves off optional parameters looks (in IL) like a call that included the parameters.

I suggest that we use a compiler trick - dump the attributes and actually implement the overloads.  This has the awesome benefit of being entirely compiler-dependent and entirely backwards-compatible even to .NET 2.0.  We can even include one overload with the attributes included, so that development tools and compilers that use the attributes can tell the user about the optional parameter information, and the existing compilers can compile against a library using the new methods.

Consider this overload based on the above demonstrated Show method.

   1:  public static class MessageBox
   2:  {
   3:      static void Show(string message, MessageBoxIcon icon)
   4:      {
   5:          Show(message, "", MessageBoxButtons.OK, icon);
   6:      }
   7:  }

This function has the advantage of being inline-able, even if it means a slightly (and I mean ever-so-slightly) hit to file size.  I'm not saying it'd be good or effective to have 10 optional parameters - just that it wouldn't be bad to have a few.

Finally, my suggestion for the syntax of how this all should work out - use the default keyword for each item when you want to specify options:

   1:  void Go()
   2:  {
   3:      MessageBox.Show("This is a test.", default, MessageBoxButtons.OK);
   4:  }

CLI implementation provides an attribute on the actual implementing method so that we can figure out which is the actual default value - the compiler then has the option of whether to call substituting in the actual value (as it's implemented in VB now) or call the correct overload (which is what the current C# compiler would do).


Another Reason to Avoid Automatic Properties

Posted by Rob

Another reason to avoid using Automatic Properties:

[Name("Simple Property Example")]
public string TestProp1

Look at the property in the debugger:

Oh wait, I can't.

I can't even set a breakpoint to let me know when the property is being accessed.  I understand not being able to see the backing store or the value component - they are after all not part of the code.  But you can't even see when they're being hit.

All I have to say is...