The goal :
To create generic interface that is parameterized by type that implements another specific generic interface.
Problem :
I'm trying to write the following related interfaces in C# and I can't decide if what I'm trying to do is possible or not.
public interface IVersion<T>
{
IVersionManager<IVersion<T>> Parent { get; }
// various other methods
}
public interface IVersionManager<T> where T : IVersion<T>
{
IReadOnlyList<T> Versions { get; }
T Current { get; }
void AddVersion(T version);
// various other methods
}
Unfortunately Visual Studio seems to find the self reference (IVersionManager<IVersion<T>>
) in the IVersion<T>
interface rather offensive.
It throws the following error:
The type '
IVersion<T>
' must be convertible to 'IVersion<IVersion<T>>
' in order to use it as a parameter 'T' in the generic interface 'IVersionManager<T>
'
That makes it sound as if it's circular but I don't think it actually is.
It makes sense to me. Am I crazy? Is this possible? I just want the child version to be able to reference it's parent manager.
Google search hasn't turned up anything. I suspect that perhaps I just don't know how to phrase the question.
As I suppose it should be:
public interface IVersion<T>
{
IVersionManager<T> Parent { get; }
// various other methods
}
public interface IVersionManager<T>
{
IReadOnlyList<IVersion<T>> Versions { get; }
IVersion<T> Current { get; }
void AddVersion(IVersion<T> version);
// various other methods
}
There is no need to define a where
constraints to achieve type safety. But the downside is that your VersionManagers
are defined not by the actual Version<T>
type but by the type T
used to define Version<T>
.
I don't know about any real way to achieve both the ability to define IVersion's
generic parameter and to make IVersionManager
generic on IVersion
using only one generic parameter.
So, to achieve true "genericness" on IVersion
implementers you'll have to use more complex types and restrictions:
public interface IVersion<T>
{
IVersionManager<T> Parent { get; }
// various other methods
}
public interface IVersionManager<TVersion, T>
where TVersion : IVersion<T>
{
IReadOnlyList<TVersion> Versions { get; }
TVersion Current { get; }
void AddVersion(TVersion version);
// various other methods
}
It is a bit superfluous and unwieldy, but allows to create more specified VersionManagers
, that are truly generic on IVersion
implementers.