Reputation: 12367
I have to say that the title is too poor to be able to describe the problem but that was the only thing I could think of. Anyway, suppose I've been given the following enum:
public enum DocumentType{
IdCard=0,
Passport,
DriversLicense
}
And I have a method that accepts a string and returns the above enum:
public DocumentType GetDocTypeByString(string docType){
switch (docType)
{
case "ID":
return DocumentType.IdCard;
case "PASS"
return DocumentType.Passport;
//and so on
}
}
Now, what if the passed string does not meet any of the switch conditions? The silliest thing would be to make the return type object, but that's something that hardly ever somebody would do it. if the enum was mine, I would add an additional value called something like "None" and return that in case of no match, but I have no control on it. Then I thought, whether it would be possible to constrain the input to certain values. As far as the C# is concerned, I am almost totally sure that it's not possible, but I decided to ask anyway. Would would you recommend in this case?
Upvotes: 4
Views: 264
Reputation: 599
This is a somewhat late answer and it was mainly something I wrote for fun, it's not elegant or fast, it's just a solution to the problem and I'm posting the code for fun and to see if anyone else comes up with another solution, and for the fact that some one somewhere might see it and it might help them solve a similar problem. DISCLAIMER; I would not use this in production code it's purely written for my own enjoyment.
void Main()
{
string p = "PASS";
var c = GetEnumNameByString<DocumentType>(p, typeof(DocumentExtendedType));
}
public enum DocumentType{ IdCard=0, Passport, DriversLicense }
public enum DocumentExtendedType { ID = 0, PASS, DRIVERS, NONE }
public TEnum GetEnumNameByString<TEnum>(string name, Type type)
{
int index = Enum.Parse(type, name).GetHashCode();
if(Enum.IsDefined(typeof(TEnum), index))
{
return (TEnum)Enum.GetValues(type).GetValue(index);
}
else
{
throw new IndexOutOfRangeException();
}
}
I do believe that the switch case is faster since it doesn't use reflection though this should work for any two enums as long as the Enums have the same structure when it comes to member values. This is just a HACK to solve the problem that enums can't inherit.
Upvotes: 0
Reputation:
There's a few things you can do here, and which one you pick depends on where you expect the input for this method to come from. If getting an invalid string represents a scenario where a programmer has made an error, the best thing to do is throw an exception.
If getting invalid strings is a very common (and hence not exceptional) scenario, e.g. if the strings come from user input, you can change your method signature in a couple of possible ways to make explicit to the consumer that your method will possibly not return a value at all:
public DocumentType? TryGetDocTypeByString(string docType) { ... }
public bool TryGetDocTypeByString(string docType, out DocumentType result) { ... }
Finally, you can combine the approaches above as follows:
public string DocumentType GetDocTypeByString(string docType)
{
DocumentType result;
if(!TryGetDocTypeByString(out result)) throw new ArgumentException("docType");
return result;
}
public bool TryGetDocTypeByString(string docType, out DocumentType result)
{
// You should probably store this as a static member of your class
var mapping = new Dictionary<string, DocumentType>() {
{ "ID", DocumentType.IdCard }
...
};
return mapping.TryGetValue(docType, out result);
}
Upvotes: 1
Reputation: 5610
This is how I would write it:
public bool GetDocTypeByString(string docType, out DocumentType enumValue){
return Enum.TryParse<DocumentType>(docType, true, out enumValue);
}
Upvotes: 1
Reputation: 1293
You could use code contracts to specify the exact values you are expecting. It's a little cleaner than the "if throw" method.
https://msdn.microsoft.com/en-us/library/dd264808%28v=vs.110%29.aspx
Upvotes: 1
Reputation: 111860
No you can't. The pattern normally used is to throw a
throw new ArgumentException("docType");
Technically even a
throw new ArgumentOutOfRangeException("docType");
would be correct, but I haven't ever seen it used outside "numeric" indexes.
For example, Enum.Parse
throw an ArgumentException
if you use illegal values, and your method seems to be something very similar to that.
Other option is to use the Enum.TryParse
pattern:
public static bool TryGetDocTypeByString(string docType, out DocumentType documentType)
{
switch (docType)
{
case "ID":
documentType = DocumentType.IdCard;
return true;
case "PASS"
documentType = DocumentType.Passport;
return true;
}
documentType = default(DocumentType);
return false;
}
Upvotes: 5
Reputation: 6014
You could make the return type nullable and do like so:
public DocumentType? GetDocTypeByString(string docType){
switch (docType)
{
case "ID":
return DocumentType.IdCard;
case "PASS"
return DocumentType.Passport;
//and so on
default: return null;
}
}
Upvotes: 4