The reason that it fails is because TComponent
could actually be some other implementation of IComponent<TKey, TComponent>
. Just because Component
implements the interface doesn't mean that nothing else can :)
One way round this would be to change the interface:
public interface IComponent<TKey, TComponent>
where TComponent : IComponent<TKey, TComponent>
{
TComponent Parent { get; }
void Register(TKey key, IComponent<TKey, TComponent> component);
void RegsiterWith(TKey key, IComponent<TKey, TComponent> component);
}
Whether that's feasible in your situation I don't know, but it would certainly avoid the type issue.
Another option would be to cast this
as spender suggested. This could fail at execution time, but in reality unless you do create an alternative implementation, it won't. It's slightly annoying, having to cast when using generics, but occasionally it happens.
EDIT: Here's an example of how it could go wrong:
public class Other : IComponent<string, Other>
{
// Implement interface
}
Now what happens if you create a Component<string, Other>
? It satisfies the constraint with no problems... but a Component
isn't an Other
...
Now you could change your constraint like this:
public class Component<TKey, TComponent> : IComponent<TKey, TComponent>
where TComponent : Component<TKey, TComponent>
i.e. constrain TComponent
on Component
instead of IComponent
. That still has issues though:
public class FooComponent : Component<string, FooComponent> {}
public class BarComponent : Component<string, FooComponent> {}
Here, you probably want BarComponent
to have a TComponent
of itself, but it's got a different component. The code you've shown so far will probably be okay, but this sort of quirk may hamper other goals. Worth considering...
Oh, and if you're happy to make Component
sealed, at that point the changed constraint is enough (I think!).