Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

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.

share|improve this question
3  
You would need to expand on the "compatibility/serialization issues" - this is overly broad otherwise. –  Oded Nov 6 '13 at 13:37
2  
So, this is a serialization & versioning issue? –  Oded Nov 6 '13 at 13:52
1  
I can understand why deserialization of enums may be problematic if you do not readily have the enum type TaskEndState available. Is this what you mean? –  Neil Nov 6 '13 at 13:55
3  
Strings don't avoid the versioning problem. Suppose you add "TASK_END_STATE_ESCALATED" a year from now. The old version will have just as much trouble with the new string or the new enum, they will both fail or hit the default case. –  cdkMoose Nov 6 '13 at 14:05
2  
Fix your serialization issues in your serializing code. Don't change all the functions everywhere that use TaskEndState as an argument type to a string just because a small bit of code gets confused serializing enums. That just doesn't make sense to me. –  Mathew Foscarini Nov 6 '13 at 15:43

3 Answers 3

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 version 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 }
share|improve this answer
    
Nice point, but the question is about comparison vs. const string. –  Yosi Nov 6 '13 at 15:35
    
@Yosi You say string is better than enum, because of versioning issues. I'm saying you can solve those while still using enum. How does that not answer the question? –  svick Nov 6 '13 at 15:37
    
Won't trying to deserialize Timeout = 3 (from the new version of TaskEndState) with an old version TaskEndState fail? –  Yosi Nov 6 '13 at 15:41
    
@Yosi That depends on the deserializer. In any case, you usually can't expect old code to handle new format correctly. –  svick Nov 6 '13 at 15:56
    
Usually enums are serailized as names, not integers, although you can override this behavior. Example [XmlEnum("0")] Error= 0 if you wanted to emit the integer. –  Jon Raynor Nov 6 '13 at 19:48

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

share|improve this answer

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.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.