Как лить A & lt; T & gt; к A & lt; object & gt ;? [Дубликат]

У меня был тот же вопрос, но потом у меня был момент «духа». Вместо записи

x ~ y

напишите

y ~ x

Очевидно, что это соответствует «x» вместо «y», но отвечает «есть ли совпадение?». вопрос и простой обход DOM могут привести вас к правильному элементу более эффективно, чем цикл в javascript.

Я понимаю, что исходный вопрос был вопросом CSS, поэтому этот ответ, вероятно, совершенно не имеет значения, но другие пользователи Javascript могут споткнуться на вопрос через поиск, как я.

19
задан Jefim 20 August 2010 в 08:06
поделиться

3 ответа

RepositoryBase<EntityBase> является не базовым классом MyEntityRepository. Вы ищете общую дисперсию , которая существует в C # в ограниченной степени, но здесь не применима.

Предположим, что у вашего класса RepositoryBase<T> был такой метод:

void Add(T entity) { ... }

Теперь рассмотрим:

MyEntityRepository myEntityRepo = GetMyEntityRepo(); // whatever
RepositoryBase<EntityBase> baseRepo = (RepositoryBase<EntityBase>)myEntityRepo; 
baseRepo.Add(new OtherEntity(...));

Теперь вы добавили другой тип сущности в MyEntityRepository ... и это не может быть прав.

В принципе, общая дисперсия является безопасной только в определенных ситуациях. В частности, общая ковариация (именно это вы описываете здесь) безопасна только тогда, когда вы только когда-либо получаете значения «API»; общая контравариантность (которая работает наоборот) безопасна только тогда, когда вы когда-либо вводили значения в API (например, общее сравнение, которое может сравнивать любые две формы по площади, можно рассматривать как сравнение квадратов).

В C # 4 это доступно для общих интерфейсов и общих делегатов, а не для классов - и только для ссылочных типов. См. MSDN для получения дополнительной информации, прочитайте & lt; plug & gt; прочитайте C # в глубине, 2-е издание , глава 13 & lt; / plug & gt; или блога Эрика Липперта по этой теме. Кроме того, я рассказал об этом в NDC в июле 2010 года - видео доступно здесь .

27
ответ дан Jon Skeet 19 August 2018 в 11:32
поделиться
  • 1
    Спасибо Jon, как за объяснение, так и за ссылку на очень интересный материал. Я обязательно подумаю о том, чтобы прочитать книгу и посмотреть видео. – Jefim 20 August 2010 в 08:42
  • 2
    Кажется, что ссылка на ваше видео нарушена. – Zachary Burns 26 June 2018 в 18:50
  • 3
    – Jon Skeet 27 June 2018 в 06:20

Всякий раз, когда кто-то задает этот вопрос, я пытаюсь взять их пример и перевести его на что-то, используя более известные классы, которые явно незаконны (это то, что сделал Джон Скит в своем ответе ;

Давайте заменим MyEntityRepository на MyStringList, например:

class MyStringList : List<string> { }

Теперь вам кажется, что вы хотите MyEntityRepository, который должен быть применим к RepositoryBase<EntityBase>, причем рассуждение состоит в том, что это должно быть возможным, поскольку MyEntity происходит от EntityBase.

Но string происходит от object, не Это? Таким образом, по этой логике мы должны были бы сделать MyStringList для List<object>.

Посмотрим, что произойдет, если мы допустим это ...

var strings = new MyStringList();
strings.Add("Hello");
strings.Add("Goodbye");

var objects = (List<object>)strings;
objects.Add(new Random());

foreach (string s in strings)
{
    Console.WriteLine("Length of string: {0}", s.Length);
}

Uh -ой. Внезапно мы перечислим List<string>, и мы наталкиваемся на объект Random. Это нехорошо.

Надеюсь, это затруднит понимание проблемы.

13
ответ дан Community 19 August 2018 в 11:32
поделиться

Это требует ковариации или контравариантности, поддержка которых ограничена в .Net и не может использоваться для абстрактных классов. Вы можете использовать дисперсию на интерфейсах, так что возможным решением вашей проблемы является создание IRepository, который вы используете вместо абстрактного класса.

    public interface IRepository<out T> where T : EntityBase { //or "in" depending on the items.
    }
    public abstract class RepositoryBase<T> : IRepository<T> where T : EntityBase {
    }
    public class MyEntityRepository : RepositoryBase<MyEntity> {
    }

    ...

    IRepository<EntityBase> baseRepo = (IRepository<EntityBase>)myEntityRepo;
7
ответ дан Mark H 19 August 2018 в 11:32
поделиться
Другие вопросы по тегам:

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