I've run into this issue a few times. I have preexisting framework objects that do not share a common ancestor. An example of this would be a class representing a an environment variable and a class representing a key in a config file. Both have a key and a value, and for the intents of my use, that is the part that I'm really concerned about, just the key and value.
If both classes shared a common ancestor I could use that when passing them around and performing operations on them, but they don't. I've managed to handle it clumsily by having a class which accepts and object and has key and value properties that do type checking, but it's gross -- I can pass instances of this class around but don't really like it -- I'd really like it if I could throw compile time errors instead of runtime errors (I tried doing multiple constructors taking advantage of argument overloading but that requires a new constructor for every supported type, which is also gross). I tried doing a generic type in C#, but that didn't really work out because I can't filter to where the item is an EnvironmentVariable OR a ConfigEntry. Is there a better more elegant way to do this?
public class KeyValueAccessibleType
{
private readonly object backingObject
public KeyValueAccessibleType(object Backer)
{
switch(Backer.GetType().Name())
{
case "EnvironmentVariable"
case "ConfigEntry"
backingObject = Backer;
break;
default:
throw new NotImplimentedException($"Unable to use backing object of type {Backer.GetType().Name()}")
}
backingObject = Backer
}
public string GetKey()
{
switch(backingObject.GetType().Name())
{
case "EnvironmentVariable"
return (backingObject as EnvironmentVariable).GetConfigKeyFunction()
case "ConfigEntry"
return (backingObject as ConfigEntry).GetConfigKeyFunction()
default:
throw new NotImplimentedException($"Unable to use backing object of type {backingObject.GetType().Name()}")
}
}
public void SetKey(string Key) {...} // Uses a switch statement like GetKey()
public string GetValue() {...} // Uses a switch statement like GetKey()
public void SetValue(string Key) {...} // Uses a switch statement like GetKey()
}
KeyValueAccessibleType
to an interface with the methods you need, then implement one concrete classEnvironmentVariableKeyValueAccessibleType
and anotherConfigEntryKeyValueAccessibleType
. You can then have a Factory which instantiates the correct implementation depending on whatever criteria you have. Your clients only depend on the interface, which means you can swap the concrete implementation at any time.