Long story short, I'm creating a factory that looks a bit like this:
public static ITag GetByTagName(string tagName)
{
tagName = tagName.ToLower();
switch (tagName)
{
case "devicevar":
return new DeviceVar();
case "devicefilter":
return new DeviceFilter();
}
return null;
}
But I also need a method that checks if tagName
corresponds to an ITag. Essentially I'm checking to see if GetByTagName
would return null without actually running it:
private List<string> tagNames = new List<string> { "devicevar", "devicefilter" };
public static bool IsValidTagName(string tagName)
{
return tagName.Contains(tagName);
}
See how we have some ugly duplication there? I don't want to specify the possible values for tagName
twice. I could always change my method so it uses the factory to try and instanciate an ITag and if it returns null, then I know it wasn't a valid value. But this just seems wasteful:
public static bool IsValidTagName(string tagName)
{
return GetByTagName(tagName) != null;
}
There must be a better way
NOTE:
I have a good (albiet longwinded) reason for needed to make this check, and it's not
"Would GetByTagName return an ITag if I gave it this string? Yes? Okay, call GetByTagName"
You can create dictionary of type Dictionary<string, Type>
which will map tag types to their names.
Dictionary<string, Type> tags = new Dictionary<string, Type>() {
{ "devicevar", typeof(DeviceVar) },
{ "devicefilter", typeof(DeviceFilter) }
};
Use ContainsKey
to check if name is valid:
public static bool IsValidTagName(string tagName)
{
return tags.ContainsKey(tagName);
}
Use Activator to create instances:
public static ITag GetByTagName(string tagName)
{
tagName = tagName.ToLower();
if (!IsValidTagName(tagName))
throw new ArgumentException(); // or return null
return (ITag)Activator.CreateInstance(tags[tagName]);
}
UPDATE (for performance) Instead of storing type in dictionary, store creation methods there:
var tagsFactory = new Dictionary<string, Func<ITag>>() {
{ "devicevar", _ => new DeviceVar() },
{ "devicefilter", _ => new DeviceFilter() }
};
And getting tags will look like:
return tagsFactory[tagName]();