Using Enums in Contracts

Jul 27, 2008 at 2:14 AM
I'm trying to migrate a custom plug-in framework I created to System.Addin. My host application loads plug-ins that perform long-running asynchronous operations and report their status. I had been using an enum to represent different plug-in states, such as started, working, sleeping, etc.

Using System.Addin, what's the best way to pass an enum in the contract? Do I use an int? If so, do I need to convert that to an enum on both the addin and host side? Is it safe to use some sort of utility assembly that's referenced on both sides? 
Jul 28, 2008 at 12:38 AM
This probably isn't the best way to do it, but I am doing something similar.  I define the enum in a .cs file, and I build a link to that file into both the host and add-in views.  In the contract I pass the value as an int and convert on both sides.

I read somewhere that if you want to put the enum into a utility assembly that's referenced on both sides that it needs to be loaded into the Global Assembly Cache before it can be referenced; this approach avoids that need, in case that is a problem.

Jul 28, 2008 at 4:20 PM
Thanks, Bob. I was afraid of having to do something like that.
If anyone knows of a better way to pass enums, I'd be very interested in hearing it!
Jul 29, 2008 at 11:38 AM
Using a shared assembly introduces a dependency that the contracts and adapters were designed to avoid in the first place, so I wouldn't advise that. Admittedly, it's probably less of an issue with something like an enumeration, but imagine if you want the enumeration values to differ on either side of the contracts.

To do this "properly" (ie. with greatest code clarity and without introducing the aforementioned dependency), you should define the enumeration in the contracts, and in both views. Yes, I mean define the enumeration three times. The adapters then translate between the contract enumeration and the corresponding view enumerations.

You could skip defining the enumeration in the contract if you like and instead marshal an int across the boundary. However, this will yield adapter code that is harder to read and more prone to mistakes.

HTH,
Kent
Jul 29, 2008 at 1:25 PM
Hi Kent, I used the approach you suggested. (Three identical enums... what happened to the DRY principle?)

I found the Common Pipeline Scenario sample helpful. An enum is included as one of the examples. http://www.codeplex.com/clraddins/Release/ProjectReleases.aspx?ReleaseId=9241
Jul 29, 2008 at 3:27 PM
I agree this can feel very anti-DRY at times. However, sharing the code is not really an option because that creates the dependency that we're trying to avoid. Of course, if you're happy to have that dependency set in stone (much like your dependency on, say, System.String) then by all means put it in a shared assembly registered in the GAC. But please be wary of the consequences this will have on your ability to evolve your software over time.

If you're happy to have all instances of the enumeration in the same namespace (I certainly am not), then you can use a link to include the same physical file into each project. That way, you only write the enumeration once but it is built into each project as its own type. If you ever need to have the enumeration differ in one project, you can break the link and then create it (without repeating yourself, because it will be different). As I say though, the big drawback here is that you need to choose a namespace that makes sense in both views and your contracts, and your adapter code will be even more error-prone and confusing as a result.

HTH,
Kent