Reputation: 1040
I have created this simple generic interface:
public interface IInitializerSettings<in ViewerType> where ViewerType : Component
{
void Apply(ViewerType dataViewer);
}
And added an implementation for it:
public class MenuSettings : IInitializerSettings<CustomGridLayout>
{
public void Apply(CustomGridLayout dataViewer)
{
Debug.Log("Applied");
}
}
public class CustomGridLayout : CustomLayout
{
// The implementation code
}
Now I try to use it like that:
public IInitializerSettings<CustomLayout> GetDefaultSettings()
{
return new MenuSettings();
}
But I get this error "Cannot convert type MenuSettings to return type IInitializerSettings"
I don't understand why it isn't allowed, CustomGridLayout
inherits CustomLayout
.
All I could find is this question, but this solution doesn't work for me (I can't use the out
keyword).
Upvotes: 0
Views: 61
Reputation: 5261
The reason you cannot do this is because for a contravariant interface (specified by your use of in
for the generic type parameter) you cannot implicitly convert it to an instance of a less derived type. I think the bullet points in the docs explains it fairly ok, if you think in terms of IEnumerable<T>
(covariant) and Action<T>
(contravariant).
As Selvin mentions in the comments the Apply
method in MenuSettings
expects an instance of CustomGridLayout
, so trying to cast MenuSettings
to IInitializerSettings<CustomLayout>
is not possible because public void Apply(CustomGridLayout dataViewer)
cannot handle a CustomLayout
as input. Let me give an example:
public class CustomLayout
{
public void SetupCustomLayout() { ... }
}
public class CustomGridLayout : CustomLayout
{
public void SetupGrid() { ... }
}
public class MenuSettings : IInitializerSettings<CustomGridLayout>
{
public void Apply(CustomGridLayout dataViewer)
{
dataViewer.SetupGrid();
}
}
// Later in the code...
var menuSettings = new MenuSettings();
// This cast is what GetDefaultSettings() is trying to do
var genericSettings = (IInitializerSettings<CustomLayout>)menuSettings;
var layout = new CustomLayout();
// Looking at the type of 'genericSettings' this following line should be possible
// but 'MenuSettings.Apply()' is calling 'dataViewer.SetupGrid()' which doesn't exist
// in 'layout', so 'layout' is not a valid input
genericSettings.Apply(layout);
So in relation to the docs you have defined IInitializerSettings<ViewerType>
as a contravariant interface, but are trying to use it as a covariant interface - which is not possible.
Upvotes: 3