У меня был тот же вопрос, но потом у меня был момент «духа». Вместо записи
x ~ y
напишите
y ~ x
Очевидно, что это соответствует «x» вместо «y», но отвечает «есть ли совпадение?». вопрос и простой обход DOM могут привести вас к правильному элементу более эффективно, чем цикл в javascript.
Я понимаю, что исходный вопрос был вопросом CSS, поэтому этот ответ, вероятно, совершенно не имеет значения, но другие пользователи Javascript могут споткнуться на вопрос через поиск, как я.
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 года - видео доступно здесь .
Всякий раз, когда кто-то задает этот вопрос, я пытаюсь взять их пример и перевести его на что-то, используя более известные классы, которые явно незаконны (это то, что сделал Джон Скит в своем ответе ;
Давайте заменим 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
. Это нехорошо.
Надеюсь, это затруднит понимание проблемы.
Это требует ковариации или контравариантности, поддержка которых ограничена в .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;