Question

I was recently told that using Enum:

public enum TaskEndState { Error, Completed, Running }

may have compatibility/serialization issues, and thus sometimes it's better to use const string:

public const string TASK_END_STATE = "END_STATE";
public const string TASK_END_STATE_ERROR = "TASK_END_STATE_ERROR";
public const string TASK_END_STATE_COMPLETE = "TASK_END_STATE_COMPLETE";
public const string TASK_END_STATE_RUNNING = "TASK_END_STATE_RUNNING";

Can you find practical use case where it may happen, is there any guidelines where Enum's should be avoided?

Edit: My production environment has multiple WFC services (different versions of the same product). A later version may/or may not include some new properties as Task end state (this is just an example). If we try to deserialize a new Enum value in an older version of a specific service, it may not work.

Was it helpful?

Solution

You don't say how exactly are you serializing the Enum, which is important here. I'm going to assume that you serialize it as the underlying integral value. In that case, your current code indeed has a versioning issue, if you add a new value into the middle of the Enum.

For example, in your current code, Error is 0, Completed is 1 and Running is 2. Now imagine you changed the code to:

public enum TaskEndState { Error, Timeout, Completed, Running }

Suddenly, what you saved as Running (old 2) will be read as Completed (new 2), which is not correct.

The best way to deal with this is to explicitly specify the numeric values for each enum member and never change them. You can add new values laster, but they have to have a new integer value. For example, the original:

public enum TaskEndState { Error = 0, Completed = 1, Running = 2 }

And the modified version:

public enum TaskEndState { Error = 0, Timeout = 3, Completed = 1, Running = 2 }

OTHER TIPS

There is no right answer for this question. It boils down to how explicit you want the contract to be.

On one hand, you could send this data simply as an xsd:string element named TaskEndState. Here, the contract take any string in the message. Validation will have to be performed in code to verify the string sent in the message matches a known value in the code. New codes can be added without changing the contract. This is a less explicit contract. This type of contract is more flexible to change, but validation is no longer being performed exclusively at the schema level as some validation will have to occur inside the code.

On the other hand, you could define a restriction (enumeration) on the xsd:string element that will only take in values defined. Validation will occur at the schema level only. New codes can be added, but that changes the contract. This is the explicit contract. This type of contract is less flexible to change, but validation is still performed in one place, at the schema level. In some cases this is desireable because schema validation is performed in centralized locations and the general consensus is that message validation is seprated from actual message processing. But, since the contract has changed, callers will have to re-test and validate that the additional restrictions did not break anything.

In general, I usually go with enums because I like my contracts to be explicit as possible. But, there are no absolutes.

In your case, if new strings are not added that often, I'd go with the enum. If TaskEndState data is very volatile (changes constantly) I would go with the generic string.

There are some good articles online one how to handle the restrictions. Here is one such link:

http://www.xml.com/pub/a/2003/02/05/wxs-enum.html?page=1

For compatibility management, enum vs string is a red herring -- either your app has some understanding of "data document" schema version or not. If it does, then this is a rather mundane implementation detail. If you don't you've got the same problem either way.

How I'd handle this with WCF is make the public-facing layer a thin wrapper that is feeding data documents with some notation of version into internals that can handle it properly. Loads of ways to get to "handle it properly" and alot of that depends on specifics of your app so I can't give an educated answer to that question here.

Licensed under: CC-BY-SA with attribution
scroll top