Понимание наследования и назначения универсального интерфейса [duplicate]

Если вы используете версию Android «23» или «23+», приложение покажет вам ошибки, когда вы пытаетесь получить доступ к чему-либо, что требует разрешения пользователя. Вы должны просить разрешения во время выполнения, даже если вы объявили эти разрешения в манифесте Android.

Проверьте это: https://developer.android.com/training/permissions/requesting. html

Но если вы создали все свое приложение и не хотите меняться в каждом месте, достаточно немного обмануть.

Перейдите в раздел «Сборка. gradle "и изменить целевую версию Sdk на менее чем 23, например 22, 21.

75
задан Henk Holterman 27 July 2015 в 09:17
поделиться

2 ответа

С помощью <out T> вы можете обрабатывать ссылку на интерфейс как одну вверху в иерархии.

С помощью <in T> вы можете обрабатывать ссылку на интерфейс как одну вниз в hiearchy.

Позвольте мне объяснить это на более английском языке.

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

Итак, с вашим списком животных (который содержит животных разных типов), вы может сказать, что у всех животных есть имя, поэтому, очевидно, было бы безопасно получить имя всех животных.

Однако, если у вас есть только список рыб, но вам нужно относиться к ним как к животные, это работает? Интуитивно, он должен работать, но в C # 3.0 и ранее этот фрагмент кода не будет компилироваться:

IEnumerable<Animal> animals = GetFishes(); // returns IEnumerable<Fish>

Причиной этого является то, что компилятор не «знает», что вы намерены, или может , делать с коллекцией животных после того, как вы ее извлекли. Для всех, кто знает, может существовать путь через IEnumerable<T>, чтобы вернуть объект в список, и это потенциально позволит вам помещать животное, которое не является рыбой, в коллекцию, которая должна содержать только рыбу .

Другими словами, компилятор не может гарантировать, что это недопустимо:

animals.Add(new Mammal("Zebra"));

Таким образом, компилятор просто отказывается компилировать ваш код. Это ковариация.

Давайте посмотрим на контравариантность.

Поскольку наш зоопарк может обрабатывать всех животных, он, безусловно, может обрабатывать рыбу, поэтому давайте попробуем добавить рыбу в наш зоопарк.

В C # 3.0 и ранее это не компилируется:

List<Fish> fishes = GetAccessToFishes(); // for some reason, returns List<Animal>
fishes.Add(new Fish("Guppy"));

Здесь компилятор мог разрешить эту часть кода, даже если метод возвращает List<Animal> просто потому, что все рыбы являются животными, поэтому, если мы просто изменили типы на это:

List<Animal> fishes = GetAccessToFishes();
fishes.Add(new Fish("Guppy"));

Тогда это сработает, но компилятор не может определить, что вы не пытаетесь это сделать:

List<Fish> fishes = GetAccessToFishes(); // for some reason, returns List<Animal>
Fish firstFist = fishes[0];

Поскольку список на самом деле является списком животных, это не разрешено.

Таким образом, противоречие и коразмерность - это то, как вы обрабатываете ссылки на объекты и что вам разрешено с ними.

Ключевые слова in и out в C # 4.0 специально маркируют интерфейс как тот или другой. С помощью in вы можете поместить общий тип (обычно T) в input -позиции, что означает аргументы метода и свойства только для записи.

С помощью out, вы можете поместить общий тип в output -позиции, которые являются значениями возврата метода, свойствами только для чтения и параметрами метода out.

Это позволит вы делаете то, что намерено делать с кодом:

IEnumerable<Animal> animals = GetFishes(); // returns IEnumerable<Fish>
// since we can only get animals *out* of the collection, every fish is an animal
// so this is safe

List<T> имеет как входы, так и выходы на T, поэтому он не является ни ковариантным, ни контравариантным, но интерфейс что позволило вам добавлять объекты, например:

interface IWriteOnlyList<in T>
{
    void Add(T value);
}

позволит вам сделать это:

IWriteOnlyList<Fish> fishes = GetWriteAccessToAnimals(); // still returns
                                                            IWriteOnlyList<Animal>
fishes.Add(new Fish("Guppy")); <-- this is now safe

Вот несколько видеороликов, которые показывают понятия:

Вот пример:

namespace SO2719954
{
    class Base { }
    class Descendant : Base { }

    interface IBibbleOut<out T> { }
    interface IBibbleIn<in T> { }

    class Program
    {
        static void Main(string[] args)
        {
            // We can do this since every Descendant is also a Base
            // and there is no chance we can put Base objects into
            // the returned object, since T is "out"
            // We can not, however, put Base objects into b, since all
            // Base objects might not be Descendant.
            IBibbleOut<Base> b = GetOutDescendant();

            // We can do this since every Descendant is also a Base
            // and we can now put Descendant objects into Base
            // We can not, however, retrieve Descendant objects out
            // of d, since all Base objects might not be Descendant
            IBibbleIn<Descendant> d = GetInBase();
        }

        static IBibbleOut<Descendant> GetOutDescendant()
        {
            return null;
        }

        static IBibbleIn<Base> GetInBase()
        {
            return null;
        }
    }
}

Без эти метки могут составить следующее:

public List<Descendant> GetDescendants() ...
List<Base> bases = GetDescendants();
bases.Add(new Base()); <-- uh-oh, we try to add a Base to a Descendant

или это:

public List<Base> GetBases() ...
List<Descendant> descendants = GetBases(); <-- uh-oh, we try to treat all Bases
                                               as Descendants
117
ответ дан gcbs_fln 27 August 2018 в 02:00
поделиться

Это сообщение - лучшее, что я прочитал по этому вопросу

. Короче говоря, ковариация / контравариантность / инвариантность связана с автоматическим литьем типов (от базового до производного и вице- Versa). Эти типы типов возможны только в том случае, если некоторые гарантии соблюдаются в отношении действий чтения / записи, выполняемых на литых объектах. Читайте сообщение для более подробной информации.

5
ответ дан Hakam Fostok 27 August 2018 в 02:00
поделиться
Другие вопросы по тегам:

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