If you want separate Types for Foo and Bar the union approach is flawed. After you parse the string you need to set for null to see what if any Type was parsed. As you add more types you will have to extend to a UnionN<foo,bar,baz,whatever....>
The correct approach would be to use polymorphism
Interface Id
{
string StringRepesentation
void ParseString(string id)
object RealId
}
class FooId : Id
{
void ParseString(string id)
{
If(id.StartsWith("foo") { this.RealId = //parse out the int ..
else { throw Exception ...
}
}
class IdParser
{
public Id Parse(string id)
{
//loop through known types and return the one that matches
}
}
//now you can overload
var Id = IdParser.Parse(string);
processor.Process(id)
But overloading is ugly and the parsing at least in your example is pretty meaningless.
You could use a Union if all your Ids have the same pattern
Union<string, int> id
id.first = string.split("#")[0];
id.last = string.split("#")[1];
if(id.first = foo) { ..process foo
But you will need all the extra parsing and re serialising logic somewhere. The generic id class is a better approach because it can hold that logic.
However. You don't really give a good reason to convert the string at all. However you do things you are going to have some sort of switch, if block or loop to sort out the types. overloading and polymorphism are not really in good favour these days, its seen as complex and cumbersome compared to simple composition.
If your Ids are a simple combined key with two parts just keeping them as strings and testing for startsWith() when you load whatever object they refer to, which presumably will benefit from a Type, is the simplest approach.