Вернуть реализацию интерфейса generi c с другим типом generi c - PullRequest
0 голосов
/ 10 апреля 2020

Я создал этот простой универсальный c интерфейс:

public interface IInitializerSettings<in ViewerType> where ViewerType : Component
{
    void Apply(ViewerType dataViewer);
}

и добавил для него реализацию:

public class MenuSettings : IInitializerSettings<CustomGridLayout>
{
    public void Apply(CustomGridLayout dataViewer)
    {
        Debug.Log("Applied");
    }
}

public class CustomGridLayout : CustomLayout
{
    // The implementation code
}

Теперь я пытаюсь использовать его следующим образом:

public IInitializerSettings<CustomLayout> GetDefaultSettings()
{
    return new MenuSettings();
}

Но я получаю эту ошибку «Невозможно преобразовать тип MenuSettings в тип возвращаемого значения IInitializerSettings»

Я не понимаю, почему это не разрешено, CustomGridLayout наследует CustomLayout.

Все, что я смог найти, это этот вопрос , но это решение не работает для меня (я не могу использовать ключевое слово out).

1 Ответ

3 голосов
/ 10 апреля 2020

Причина, по которой вы не можете этого сделать, заключается в том, что для контравариантного интерфейса (указанного при использовании in для параметра типа generi c) вы не можете неявно преобразовать его в экземпляр менее производного типа. Я думаю, что маркеры в документах объясняют это довольно хорошо, если вы думаете в терминах IEnumerable<T> (ковариантный) и Action<T> (контравариантный).

Как упоминает Селвин в комментирует, что метод Apply в MenuSettings ожидает экземпляр CustomGridLayout, поэтому попытка привести MenuSettings к IInitializerSettings<CustomLayout> невозможна, поскольку public void Apply(CustomGridLayout dataViewer) не может обработать CustomLayout в качестве ввода. Позвольте мне привести пример:

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);

Итак, по отношению к документам вы определили IInitializerSettings<ViewerType> как контравариантный интерфейс, но пытаетесь использовать его как ковариантный интерфейс - который невозможно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...