Недавно я был взят за расширение пользовательского класса, чтобы выставить метод расширения LINQ для частного участника, например:
public virtual T FirstOrDefault(Expression<Func<T, bool>> predicate)
{
return _someDbSet.FirstOrDefault(predicate);
}
Некоторые члены команды сказали, что это плохо. Приведенное объяснение было чем-то вроде строки: поскольку внутренний метод является методом расширения, внешний должен быть также.
(Почему) это так плохо?
Нет большой проблемы при добавлении метода с тем же именем, что и существующий метод расширения, если он "переопределяет" функциональность этого метода расширения или сигнатуры несовместимы друг с другом (или если метод расширения может " t применяется к этому конкретному классу).
Если эти правила не применяются или вы намерены использовать их оба, это может быть действительно запутанным, какой метод вызывается в конце. Это может привести к ошибкам, поэтому я не советую использовать метод с тем же именем, что и метод расширения.
FirstOrDefault
имеет смысл, только если класс логически является коллекцией (но я предполагаю, что это немного больше, чем просто)
FirstOrDefault
прекрасно.
Приведенное объяснение было чем-то вроде строки: поскольку внутренний метод является методом расширения, внешний должен быть также.
Если это был аргумент, то это полная глупость. В логическом завершении мы не могли назвать каких-либо статических членов в членах экземпляра (поскольку методы расширения - это просто статические методы с некоторым синтаксическим сахаром, чтобы они выглядели как методы экземпляра для первого аргумента). Примените это последовательно, и вы скоро закончите либо без статических методов вообще, либо без каких-либо объектов.
Здесь есть немного проблемы:
публичный виртуальный T FirstOrDefault (предикат Expression>)
FirstOrDefault
- широко используемый метод расширения. Таким образом, у нас есть идея, что он собирается делать, когда мы это называем.
Если класс действует как коллекция, которая обертывает _someDbSet
то этот метод бессмыслен; мы можем просто использовать FirstOrDefault
который уже существует.
Если класс не действует как коллекция, которая обертывает _someDbSet
тогда этот метод может быть запутанным, поскольку он не будет действовать так, как мы ожидали бы, чтобы известный FirstOrDefault
действовал.
Если класс IEnumerable
или IQueryable
и FirstOrDefault
не делают то же самое, что и FirstOrDefault
расширения FirstOrDefault
, тогда это может быть очень запутанным, потому что одно и то же имя участника FirstOrDefault
бы другое поведение в зависимости от того, как ссылался объект, и что только очень редко хорошая вещь.
И наоборот, если бы у нас был FirstOrDefault
экземпляра FirstOrDefault
который делал то же самое, что и FirstOrDefault
, в противном случае, но делал бы это намного эффективнее, тогда это случай, когда метод маски экземпляра метода расширения - это очень хорошо; нет никакой разницы в поведении в отношении вызывающего кода, просто повышение производительности, которое является "бесплатным" до того, как этот код вызова идет, поскольку он написан точно так же, как и в любом случае.
FirstOrDefault
существующего FirstOrDefault
, но для члена, который является частным. Оборачивая это как это выставляет это.