Как вы возвращаете класс, который наследует базовый класс с общим ответом? [Дубликат]

Ничего не помогло, пока я не нашел это решение: https://stackoverflow.com/a/39068538/3995091

В Android SDK инструменты сборки с правильной версией, где показанный как установленный, но все же я получил ту же ошибку, заявив, что их невозможно найти. Когда я использовал вышеупомянутое решение, я узнал, что они действительно не установлены, хотя Android SDK считали, что это так. Установка их решила для меня.

11
задан Rachel 11 September 2014 в 17:31
поделиться

3 ответа

Это очень часто задаваемый вопрос. Давайте переименуем ваши типы:

abstract class Fruit { }                    // was BaseViewPresenter
abstract class FruitBowl<T> where T : Fruit // was BaseView
class Apple : Fruit { }                     // was LoginPresenter
class BowlOfApples : FruitBowl<Apple> {  }  // was LoginView

Теперь ваш вопрос:

У меня есть BowlOfApples, который наследуется от FruitBowl<Apple>. Почему я не могу использовать его как FruitBowl<Fruit>? Яблоко - это плод, поэтому чаша с яблоками - это миска с фруктами.

Нет, это не так. Вы можете положить банан в миску с фруктами, но вы не можете положить банан в миску с яблоками, и поэтому чаша с яблоками - это не чаша с фруктами. (И по аналогичным соображениям, миска с фруктами также не является чашей из яблок.) Поскольку операции, которые вы можете законно выполнять на двух типах, отличаются , они не могут быть совместимыми .

Вот фотография легенды StackOverflow Jon Skeet, демонстрирующая этот факт:

enter image description here [/g6]

Вы хотите, чтобы функция общая контравариантность , и поддерживается только на интерфейсах интерфейсов и делегатов , когда компилятор может доказать, что дисперсия безопасна, а когда переменный тип является ссылкой тип. Например, вы можете использовать IEnumerable<Apple> в контексте, где требуется IEnumerable<Fruit>, потому что компилятор может проверить, что вы не можете поместить Banana в последовательность фруктов.

Проведите поиск по «ковариации и ковариации C #» на этом сайте или в Интернете, и вы найдете гораздо больше информации о том, как работает эта функция. В частности, моя серия статей о том, как мы разработали и реализовали эту функцию на C # 4, начинается здесь: http://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and- контрвариантность-в-с-часть-one.aspx

39
ответ дан Eric Lippert 28 August 2018 в 14:37
поделиться

Я принял ответ Эрика, так как он дает отличное объяснение, почему то, что я хотел, было невозможно, но я также подумал, что поделюсь своим решением, если кто-то еще столкнется с этой проблемой.

Я удалил параметр generic type из моего исходного класса BaseView и создал вторую версию класса BaseView, которая включала в себя параметр типового типа и особенности для него.

Первая версия используется моим методом .Resolve() или другим кодом, который не заботится о конкретных типах, а вторая версия используется любым кодом, который действительно заботится, например, имплантация BaseView

Вот пример того, как мой код закончил поиск

// base classes
public abstract class BaseViewPresenter { }
public abstract class BaseView : UserControl 
{
    public BaseViewPresenter Presenter { get; set; }
}

public abstract class BaseView<T> : BaseView
    where T : BaseViewPresenter
{
    public new T Presenter
    {
        get { return base.Presenter as T; }
        set { base.Presenter = value; }
    }
}

// specific classes
public class LoginPresenter : BaseViewPresenter { }
public partial class LoginView : BaseView<LoginPresenter> 
{
     // Can now call things like Presenter.LoginPresenterMethod()
}

// updated .Resolve method used for obtaining UI object
public BaseView Resolve(BaseViewPresenter presenter)
{
    var type = model.GetType();
    var viewType = _dataTemplates[type];

    BaseView view = Activator.CreateInstance(viewType) as BaseView;
    view.Presenter = presenter;

    return view;
}
8
ответ дан Andrew Hanlon 28 August 2018 в 14:37
поделиться

Вы ожидаете рассматривать тип как ковариантный относительно общего аргумента. Классы никогда не могут быть ковариантными; вам нужно будет использовать интерфейс, а не (или в дополнение к) абстрактный класс, чтобы сделать его ковариантным относительно T. Вам также нужно будет использовать C # 4.0.

3
ответ дан Servy 28 August 2018 в 14:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: