Over in java I'm pretty used to working with generics and the wildcard. Things like: List<? extends Animal>
. This allows you to have a collection of subtypes of Animals and run generic routines on each element (e.g. makeNoise()
). I'm trying to accomplish this in C# but am a bit confused, since there's no wildcards.
Domain wise, what we're doing here is working with the SQL SMO libraries to collect scripts out of our database. We've got a base interface type that is extended a number of times to script and collect different objects (table, view, function, etc -- this is the T)
public interface IScripter<T> where T : IScriptable
{
IList<T> CollectScripts(params...)
}
public abstract class AbstractScripter<T> : IScripter<T> where T : IScriptable
{
....
}
public class TableScripter : AbstractScripter<Table>
{
....
}
public class ViewScripter : AbstractScripter<View>
{
....
}
So far so good. Seems like a perfectly sensible object hierarchy right? Here's what I intended to do, until I found out there's no wildcards:
public class Program
{
static void Main(string[] args)
{
// auto discover all scripter modules, table, view, etc
IList<Iscripter<? extends IScriptable>> allScripters = GetAllScripterModules();
foreach (IScripter<? extends IScriptable> scripter in allScripters)
{
IList<? extends IScriptable> scriptedObjects = scripter.CollectScripts(...);
// do something with scripted objects
}
}
}
Now since <? extends IScriptable>
doesn't exist here, what am I supposed to do instead? I've tried a number of things, generic method, just using the base type, all sorts of nasty casting, but nothing really did the trick.
What would you suggest to replace the IList<Iscripter<? extends IScriptable>
piece?
TIA
By using out
and only passing T
or other covarient T
interfaces out from the interface, you can make the interface covariant;
public interface IScripter<out T> where T : IScriptable
{
IEnumerable<T> CollectScripts(params...)
}
You then can't add to the result, because you cannot use the not covarient IList
so add separate interface for when you want to add:
public interface IScripterAddable<T> where T : IScriptable
{
//either:
IList<T> CollectScripts(params...)
//or add just what you need to, this is usually better
//than exposing the underlying IList - basic encapsulation principles
void AddScript(...)
}
Then just remove the ? extends
.
// auto discover all scripter modules, table, view, etc
IList<Iscripter<IScriptable>> allScripters = GetAllScripterModules();
foreach (IScripter<IScriptable> scripter in allScripters)
{
IEnumerable<IScriptable> scriptedObjects = scripter.CollectScripts(...);
// do something with scripted objects
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With