C
C#8mo ago
Bluestopher

Generic Class Help

Hello, I am working on a PluginManager that contains a dictionary of plugins, which are accessed via keys based off the plugin name. Plugins are generic and have a constraint that the type implements IRecord. I am having an issue with my GetPlugin method because it expects to return IPlugin<IRecord> and not the generic IPlugin<IRecord>. I’m not to sure how to define this since my dictionary of IPlugins is meant to be generic (IPlugin<T>). Does anyone have any ideas on how to fix this or implement it? Also, all my plugins are registered at startup and resolved via DI, which is why I use IRecord as my type of IPlugin since all plugins work on data that implements IRecord. I am a bit stuck currently and tried a bunch of different approaches.
public class PluginManager : IPluginManager
{
private readonly Dictionary<string, IPlugin<IRecord>> _plugins = new();

public PluginManager(IEnumerable<IPlugin<IRecord>> plugins)
{
Requires.NotNull(plugins, nameof(plugins));

plugins.ForEach(RegisterPlugin);
}

private void RegisterPlugin(IPlugin<IRecord> plugin)
{
Requires.NotNull(plugin, nameof(plugin));

if (_plugins.ContainsKey(plugin.Name))
{
throw new ArgumentException($"Unable to register plugin. A plugin with Key: \"{plugin.Name}\" is already registered.");
}

_plugins.Add(plugin.Name, plugin);
}

public IPlugin<T> GetPlugin<T>(string key)
where T : class, IRecord
{
if (!_plugins.ContainsKey(key))
{
throw new ArgumentException($"Plugin with key \"{key}\" is not registered.");
}

return _plugins[key]; // This gives me an error since it cannot return IPlugin<T> since it expects to return IPlugin<IRecord>.
}
}
public class PluginManager : IPluginManager
{
private readonly Dictionary<string, IPlugin<IRecord>> _plugins = new();

public PluginManager(IEnumerable<IPlugin<IRecord>> plugins)
{
Requires.NotNull(plugins, nameof(plugins));

plugins.ForEach(RegisterPlugin);
}

private void RegisterPlugin(IPlugin<IRecord> plugin)
{
Requires.NotNull(plugin, nameof(plugin));

if (_plugins.ContainsKey(plugin.Name))
{
throw new ArgumentException($"Unable to register plugin. A plugin with Key: \"{plugin.Name}\" is already registered.");
}

_plugins.Add(plugin.Name, plugin);
}

public IPlugin<T> GetPlugin<T>(string key)
where T : class, IRecord
{
if (!_plugins.ContainsKey(key))
{
throw new ArgumentException($"Plugin with key \"{key}\" is not registered.");
}

return _plugins[key]; // This gives me an error since it cannot return IPlugin<T> since it expects to return IPlugin<IRecord>.
}
}
2 Replies
Bluestopher
Bluestopher8mo ago
I don’t think type casting the return type for the GetPlugin is the answer for this. I believe that pushes the problem under the rug of what I am trying to do but am doing it incorrectly,
PixxelKick
PixxelKick8mo ago
Theres no way to do this that doesnt involve casting the type. You effectively want a list of IPlugin<T> but each one can have a different T, which means they have different types. At some point, some code is going to have to perform a cast to the type you need. The main question I have to ask is, what is the T is used for, like to start, what is the definition of the interface IRecord<T> look ing like at the moment?