Runtime: Сделайте интерфейсы официальным API провайдера ADO.NET вместо классов

Созданный на 26 сент. 2015  ·  174Комментарии  ·  Источник: dotnet/runtime

Из того, что я сейчас вижу на странице corefx-progress для System.Data.Common , интерфейсы (IDbCommand, IDbConnection и т. Д.) Были удалены в пользу использования абстрактных классов.

Но в новом API большинство основных методов не являются виртуальными или абстрактными. Только на DbCommand мы можем это увидеть:

public DbConnection Connection { get; set; }
public DbParameterCollection Parameters { get; }
public DbTransaction Transaction { get; set; }
public DbParameter CreateParameter();
public Task<int> ExecuteNonQueryAsync();
public DbDataReader ExecuteReader();
public DbDataReader ExecuteReader(CommandBehavior behavior);
public Task<DbDataReader> ExecuteReaderAsync();
public Task<DbDataReader> ExecuteReaderAsync(CommandBehavior behavior);
public Task<DbDataReader> ExecuteReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken);
public Task<DbDataReader> ExecuteReaderAsync(CancellationToken cancellationToken);
public Task<object> ExecuteScalarAsync();

Хотя эти методы, безусловно, можно сделать виртуальными или абстрактными, было бы гораздо полезнее вернуть реальные интерфейсы и сделать так, чтобы любой общедоступный API зависел от этих интерфейсов, а не от абстрактных классов.

Это в основном полезно при разработке библиотек. Сегодня очень сложно имитировать устройство чтения данных, чтобы заставить его возвращать определенное значение для целей тестирования. То же самое для обеспечения того, чтобы был вызван ExecuteReaderAsync, а не ExecuteReader и т. Д.

Я предлагаю вместо этого сделать фабрику провайдера интерфейсом:

public interface IDbProviderFactory {
    IDbCommand CreateCommand();
    IDbConnection CreateConnection();
    IDbConnectionStringBuilder CreateConnectionStringBuilder();
    IDbParameter CreateParameter();
}

А затем следуйте оттуда до остальной части провайдера до таких вещей, как IDbDataReader , IDbTransaction и т. Д.

Мы знаем, что в прошлом интерфейсы по какой-то причине рассинхронизировались, а абстрактные классы были сделаны официальным API, но в corefx этого больше не должно быть.

Обратите внимание, что это никоим образом не означает удаление System.Data.Common, а вместо этого заставляет классы Common реализовать эти интерфейсы, и вы не будете использовать System.Data.Common, если вы не реализуете поставщика. Вместо этого приложения будут зависеть только от интерфейсов.

Учтите, что это поможет сделать API более тестируемым на corefx 1.0.

Относится к обсуждениям dotnet / runtime # 14302 и dotnet / runtime # 15269.

area-System.Data

Самый полезный комментарий

Мы не можем добавлять участников в интерфейсы

Правильно, и это _хорошая_ особенность интерфейсов. Предпочтение абстрактных базовых классов - это самый безопасный способ помочь энтропии API, а не бороться с ней.

Хотя вам не _обязательно_ следовать принципам OOD , я бы посоветовал вам это делать при создании OO API. Короче говоря, Принцип разделения

Если вы добавляете новые методы к существующей абстракции, вы автоматически нарушаете ISP.

Вы можете решить, что вам «не нужно придерживаться SOLID», потому что вы Microsoft и работаете с BCL, поэтому «обычные правила не применяются» (не настоящие кавычки; просто перефразируя обычные контраргументы).

Я поддерживал пару проектов с открытым исходным кодом в течение 6-7 лет, и по моему опыту лучше, чтобы интерфейсы были небольшими. Если вам нужно добавить новые возможности в абстракцию, представьте новый интерфейс.

Все 174 Комментарий

Они бы переключились на абстрактные базовые классы, потому что для интерфейсов нельзя управлять версиями.

Я предполагаю, что невиртуальные методы вызывают другой виртуальный метод. Виртуальные методы снижают производительность, поэтому вы не хотите делать вещи виртуальными без надобности.

@JamesNK Понятно . Но учитывая, что .NET Core является новым API, а ADO.NET API достаточно стабилен на протяжении почти десятилетия, вы думаете, что это все еще актуальная проблема? Кроме того, говоря о доступе к базе данных, я предполагаю, что стоимость виртуальных методов меньше стоимости доступа к базе данных.

@NickCraver , @FransBouma , раз уж вам, ребята, кажется, интересен ADO.NET API, есть что сказать по этому поводу?

@YoungGah , стоит ли заниматься этим?

Я предполагаю, что невиртуальные методы вызывают другой виртуальный метод. Виртуальные методы снижают производительность, поэтому вы не хотите делать вещи виртуальными без надобности.

В процессе выполнения запроса к удаленной базе данных и обработки результатов наносекунды, потерянные на виртуальном вызове, незначительны. Кроме того, ADO.NET использует эту систему с самого начала (как и многие другие API в .NET), и никто не жаловался, что их код БД настолько медленный из-за вызовов виртуальных методов;)

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

Интерфейсы не версируются.

Производительность - лишь одна из причин не делать что-то виртуальное. Возможно, уменьшение площади под навесное оборудование? Я позволю кому-нибудь из MS сказать, почему они решили этого не делать, я мало что знаю об ADO.NET, поэтому я просто спекулирую.

@JamesNK Я думаю, что ваши опасения справедливы, но следует учитывать два важных момента:

  1. ADO.NET был в значительной степени стабильным со времен .NET 2.0, которое прошло десять лет - хотя асинхронный API был добавлен позже, он не изменил поведение API, просто добавил асинхронные аналоги - я не вижу больших изменений в парадигма драйвера базы данных в ближайшее время
  2. Предполагается, что CoreFx имеет другую идею управления версиями, поскольку вы можете просто сохранить предыдущую среду CLR для старых приложений. Таким образом, проблемы с версией интерфейса не должны иметь здесь такого влияния.

Учтите также, что даже sql-сервер на "localhost" потратит в аренде несколько миллисекунд только на то, чтобы подключиться и вернуть пустой запрос. На практике большинство быстрых_ запросов к реляционным базам данных занимают ~ 20 мсек.

Возможность имитировать API с помощью стандартных инструментов, таких как NSubstitute или Moq, сегодня гораздо более ценно для разработчика, чем экономия микросекунд при поиске виртуальных методов.

Думаю, у меня здесь нет очень твердого мнения, но вот несколько замечаний:

  • Согласитесь с вышеизложенным, что удаление виртуального и не виртуального несущественно в API для доступа к базе данных.
  • Базовые классы действительно позволяют ADO.NET предоставлять реализации, я предполагаю, что это то, о чем большинство невиртуальных неабстрактных методов - перегрузка ExecuteReader, которая не принимает CommandBehavior, передает CommandBehavior.Default перегрузке это делает. Если вы переключитесь на интерфейсы, каждый провайдер должен будет реализовать ExecuteReader () с точно таким же шаблоном ...
  • Не уверен, что это справедливо для всех основных фреймворков имитирования, но, по крайней мере, в Moq разве не так просто имитировать базовый класс, как и интерфейс?

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

Я согласен с @roji по всем его пунктам.

@roji просто примечание, я не предлагаю отбрасывать базовые классы, я предлагаю добавить интерфейсы в качестве API по умолчанию. Базовые классы по-прежнему могут реализовывать поведение по умолчанию.

Что касается тестирования, у меня были огромные проблемы с тестированием, если мой API вызывал правильные методы. Чтобы проверить, получил ли ExecuteDataReader правильные параметры, например, вы должны проверить другой защищенный метод, который вызывается внутри с другими параметрами. Это далеко не идеально.

В настоящее время, если я не ошибаюсь, единственный фреймворк, который может имитировать ADO.NET API, - это фреймворк MS Fakes, который может имитировать абсолютно все, перехватывая вызовы. Moq и другие не могут этого сделать.

Мне интересно узнать, были ли у других подобные проблемы.

@roji просто примечание, я не предлагаю отбрасывать базовые классы, я предлагаю добавить интерфейсы в качестве API по умолчанию. Базовые классы по-прежнему могут реализовывать поведение по умолчанию.

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

Что касается тестирования, у меня были огромные проблемы с тестированием, если мой API вызывал правильные методы. Чтобы проверить, получил ли ExecuteDataReader правильные параметры, например, вы должны проверить другой защищенный метод, который вызывается внутри с другими параметрами. Это далеко не идеально.

Если я понимаю ваш сценарий (не уверен), Moq CallBase полезен для такого рода сценариев - реализации по умолчанию наследуются от базового класса.

@roji

разве ваше предложение не поддерживает более или менее все в том виде, в каком они есть в .NET (не то чтобы в этом что-то не так)?

Не совсем. Интерфейсный API был добавлен в .NET 1.0 и объявлен устаревшим в версии 2.0. Начиная с версии 2.0 интерфейсы предназначены для совместимости, но в Data.Common нет интерфейса для ProviderFactory или других классов. Также нет ничего для async API или методов 2.0 или новее.

Moq может только издеваться над тем, над чем можно посмеяться. Должен существовать какой-то виртуальный или абстрактный метод, который он может переопределить, или защищенный метод, который он может вызывать. Текущий API предоставляет метод для некоторых случаев, но не для большинства из них. Есть много вещей, которые являются внутренними, частными и недоступными, если вы не используете отражение. Только MS Fakes может это сделать, потому что он заменяет ссылку на прокладку, но это доступно только в VS Enterprise и бесполезно для проектов с открытым исходным кодом.

Похоже, у меня очень конкретный случай, но, безусловно, любой, кто когда-либо пытался издеваться над этим api, сталкивался с этой проблемой. Просто погуглите, почти каждое решение заканчивается «имитируйте устаревший интерфейс API или создайте оболочку, которую вы можете имитировать»:

@nvivo Хорошо, спасибо за дополнительные подробности - признаю, я не очень далеко зашел в издевательстве над ADO.NET.

Я не понимаю, почему вы хотите имитировать внутренние, частные и другие недоступные методы API. Разве вы не должны издеваться над общедоступными методами, которые напрямую доступны для вашего собственного кода приложения (это то, что вы пытаетесь протестировать)? Я вижу проблему с невиртуальными методами (например, перегрузка ExecuteReader () с 0 параметрами), но, учитывая, что в ADO.NET они всегда (?) Вызывают некоторую виртуальную перегрузку (например, ExecuteReader (CommandBehavior)), есть ли реальная проблема здесь?

Просто пытаясь понять сценарий вашей проблемы, вы можете привести простой пример?

@nvivo В настоящее время мы не планируем вводить интерфейсы из-за проблемы с

@roji У меня были случаи, когда я хотел убедиться, что вызывается определенная перегрузка ExecuteReader, а не «какая-либо из перегрузок». Такие вещи есть только в библиотеках, а не в пользовательском коде.

@YoungGah, спасибо за информацию. Тогда я закрываю это.

Имеют ли люди, ответственные за это изменение, какое-либо представление о его последствиях? Основные интерфейсы ADO.NET существуют уже более десяти лет, а доступ к данным является центром большинства бизнес-приложений. Мне сложно понять, почему намеренное нарушение стольких существующих кодовых баз не является высшим приоритетом? Это одни из наиболее важных высокоуровневых интерфейсов в .NET, устраняющие эти нарушения в каждой библиотеке доступа к данным ADO .NET и, как следствие, в каждом проекте, использующем ее. Их удаление создает искусственную фрагментацию, вызывая разочарование и замешательство, которые затрудняют внедрение CoreCLR.

Вы по-прежнему можете версии интерфейсов и сделать их совместимыми с исходным кодом, просто добавив методы расширения для любого нового API за IDbCommand , например:

public interface IDbCommand
{
    //...
}

public class DbCommand : IDbCommand
{
    void NewApi();
}

public static class DbCommandExtensions
{
    public static void NewApi(this IDbCommand cmd)
    {
        ((DbCommand)cmd).NewApi();
    }
}

Основной интерфейс IDbCommand никогда не должен меняться после выпуска DNX, и вы можете продолжить добавление функций с помощью стратегии, описанной выше. Вы также можете позже (в основной критической версии) свернуть эти расширения и объединить их в основной интерфейс. В любом случае мы получаем основные стабильные интерфейсы ADO.NET, которые имеют решающее значение для миграции существующих кодовых баз и, следовательно, для принятия CoreCLR.

@Davkean попросил меня предоставить конкретные примеры того, какое влияние окажет удаление основных интерфейсов ADO .NET. Я не могу представить, чтобы это изменение рассматривалось без оценки неизмеримого воздействия, которое оно окажет на существующую экосистему .NET, но, опять же, это также было сделано, поэтому есть вероятность, что оно не было учтено - что я собираюсь здесь предположить - в нем не было.

Несмотря на роль EF в качестве ORM по умолчанию для .NET и его выдающийся успех в захвате значительной части рынка, все еще существует большое количество разработчиков .NET, которые предпочитают вместо этого использовать альтернативные ORM по ряду различных причин. Например, важной особенностью, связанной с CoreCLR, является то, что они имеют первоклассную поддержку, работающую на Mono / Linux / OSX, а также поддержку нескольких альтернативных СУБД. Поскольку CoreCLR активно используется на рынке разработчиков Linux / OSX, чем больше будет поддержки альтернативных RDBM, тем лучше. Еще одна важная черта группы разработчиков, использующих Micro ORM, заключается в том, что они оценивали значения по умолчанию за пределами экосистемы MS, чтобы выбрать наиболее подходящую для них ORM. Из всего, что я видел, существует высокая корреляция между активными разработчиками .NET OSS (то есть анти-Dark Matter) и разработчиками, которые применяют Micro ORM, также я ожидаю, что это будет иметь высокую корреляцию с ранними последователями CoreCLR, чье основное ценностное предложение заключается в для разработки на OSX / Linux. Вот некоторые из причин, по которым было бы полезно включить окружающую экосистему .NET в процесс принятия решений, когда вы делаете принципиально принципиальный выбор в дизайне, подобный этому.

Альтернативные загрузки ORM

Беглый взгляд на загрузки NuGet дает представление о том, как выглядит рыночная доля, не относящаяся к EF:

NHibernate - 1 млн +
Dapper - 1 млн +
OrmLite -
Simple.Data -
PetaPoco - ~ 100 тыс.
NPoco - 30 тыс. +

Реальные числа намного больше, чем это, так как многие Micro ORM, такие как Dapper, Massive, PetaPoco, NPoco и т. Д., Были разработаны для размещения в одном файле .cs, поэтому NuGet не сообщает о его истинном использовании. Существуют также ORM с закрытым исходным кодом, такие как LLBLGen Pro, которые имеют большую базу пользователей, но NuGet не сообщает об их использовании, также я уверен, что пропустил ряд других ORM, о которых я забыл / не знаю.

Влияние на альтернативные ORM

Благодаря GitHub мы можем быстро найти, сколько разных исходных файлов содержат ядро.
Это изменение затронуло интерфейсы IDbConnection , IDbCommand и IDataReader ADO .NET:

IDbConnectionIDbCommandIDataReader
NHibernate59181132
Dapper1721 год17
OrmLite1795426
Simple.Data29276
NPoco4103

Примечание: эти результаты показывают только исходные файлы, фактическое количество неработающих ссылок намного выше.

Влияние на исходный код клиента

Фактическое влияние этого изменения также распространяется на все зависимости проектов, использующих эти ORM.
К сожалению, эффект не ограничивается внутренними реализациями, так как он также ломает клиента.
исходный код, как и многие Micro ORM, - это просто методы расширения интерфейсов ADO.NET, поэтому клиент
код выглядит так:

IDbConnection db = ...

//Dapper
db.Query<Dog>("select Age = <strong i="49">@Age</strong>, Id = @Id", new { Age = (int?)null, Id = guid });

//OrmLite
db.Select<Author>(q => q.Name.StartsWith("A"));

Одна особенность расширяемости от использования методов расширения заключается в том, что эти ORM являются «открытыми», и клиенты могут расширять ORM с помощью своих собственных первоклассных API, добавляя методы расширения в свои собственные проекты - они также не работают.

Очевидно, что любой исходный код, который передает IDbConnection теперь также запрещен для работы с CoreCLR.

Например, основные интерфейсы ADO.NET активно используются во всех высокоуровневых средах, таких как ServiceStack, поскольку это минимальная зависимость для обеспечения доступа к данным из нескольких СУБД. Также предполагалось, что из всех классов, которые вряд ли будут изменены, это будут основные интерфейсы ADO.NET.

Резюме

Я лично удивлен, что у .NET когда-либо было будущее без этих интерфейсов.
Интерфейсы по своей конструкции ориентированы на конкретные цели, что позволяет использовать несколько реализаций, а ADO.NET - это одна из них.
из наиболее важных «моделей открытых поставщиков» в .NET. Я понятия не имею, какие приоритеты привели к удалению этих интерфейсов, но как массивным существующим базам кода .NET, которые полагаются на эти интерфейсы, так и альтернативной экосистеме EF .NET следует уделить гораздо более высокий приоритет. Это вызывает значительные сбои и является основным препятствием, необходимым для поддержки существующих платформ .NET 4.x и CoreCLR, вызывая нетривиальное количество дополнительной сложности, которая должна применяться ко всем существующим базам кода, затронутым этим.

Текущее мнение таково, что ADO.NET/CoreCLR перепроектируется, чтобы обеспечить первоклассную поддержку EF и SQL Server, при этом остальная часть экосистемы игнорируется - непрозрачные критические решения, подобные этому, только усиливают этот стереотип. .

Как предыдущий член группы .NET (сейчас я работаю над Roslyn), я принимал активное участие в первоначальной разработке новых общих данных вместе с командами SQL и Entity Framework. В данный момент я не участвую в этом, но могу добавить некоторую предысторию, чтобы помочь исправить некоторые утверждения, которые я вижу в твиттере и выше.

Текущая разработка System.Data.Common для .NET Core началась в декабре 2012 года, примерно за 2 года до того, как мы открыли исходный код.

Цели:

  • Разработайте современную поверхность для .NET Core, которая уменьшит дублирование концепций ( IDbConnection vs DbConnection ), путаницу, ошибки и проблемы с распределением слоев (разделите SqlClient из DataCommon, разделите DataSet из основных абстракций) из оригинальный дизайн из .NET 1.0. Тот, который будет легко воспринят как существующими потребителями, так и _ новыми_ разработчиками .NET Framework.
  • Разрешите поставщикам и потребителям создать единый двоичный файл / исходный код для .NET Core, а затем запустить этот же двоичный файл на .NET Framework. Обратите внимание, обратное не было целью; возможность взять двоичный файл / исходный код .NET Framework и запустить его без каких-либо изменений в .NET Core.

Исправление нескольких распространенных вещей:

  • Интерфейсы в их нынешнем виде не поддерживают версии. Мы не можем добавлять элементы в интерфейсы, а предложение, приведенное выше, предоставленное @mythz через методы расширения, требует, чтобы поставщики в любом случае были производными от абстрактных базовых классов.
  • System.Data.Common _не_ отошла от модели поставщика. Интерфейсы были удалены, поскольку они были устаревшей концепцией .NET 1.0, которая была заменена / продублирована абстрактными базовыми классами, представленными в .NET 2.0. В то время, когда мы приняли это решение, каждый провайдер, которого мы могли найти, был производным от базовых классов.
  • Как и интерфейсы, базовые классы можно смоделировать.
  • Мы понимали, что потребуются некоторые изменения для тех, кто использует интерфейсы .NET 1.0, однако это очень простой порт для перехода к базовым классам. Например, просмотрите эти несколько строк изменений для AutoMapper: (https://github.com/AutoMapper/AutoMapper.Data/blob/master/AutoMapper.Data/DataReaderMapper.cs#L14).

Что-то я не понимаю:

Мы не можем добавлять участников в интерфейсы

Как еще не добавлять элементы в интерфейсы CoreCLR, можно их полностью вырвать?

предложение выше, предоставленное @mythz через методы расширения, требует, чтобы поставщики в любом случае были производными от абстрактных базовых классов.

Важной частью является то, что интерфейсы существуют и позволяют компилировать исходный код, который ссылается на них.

Если вы не хотите обновлять интерфейсы, исправьте их EOL, просто восстановите интерфейсы такими, какими они были до того, как они были извлечены, и уменьшите нагрузку, которая теперь возлагается на все остальные библиотеки, использующие их. Я имею в виду, что эти основные интерфейсы никогда не устаревали без предупреждения или пути миграции. И все же нас наказывают за то, что мы используем опубликованный, хорошо известный, стабильный API в качестве неотъемлемой части наших библиотек?

это очень простой порт для перехода к базовым классам.

Это необходимо добавить в каждый исходный файл, который ссылается на интерфейсы ADO.NET и заставляет заказчиков засорять свой код настраиваемыми символами сборки.

Похоже, здесь нет такой же заботы об обратной совместимости, но намеренное нарушение существующих клиентов в будущем выпуске просто не вариант (я удивлен, что это даже рассматривается с гораздо большей долей рынка ADO .NET). Мы не можем сломать существующих клиентов 4.x, и все же нас просят поддержать CoreCLR - так что же делать с существующими библиотеками 4.x, которые хотят поддерживать существующую обратную совместимость, а также поддерживают CoreCLR? Должны ли мы также дублировать документы / примеры?

Как еще не добавлять элементы в интерфейсы CoreCLR, можно их полностью вырвать?

Поверхность .NET Core должна быть бинарно совместимой с .NET Framework, чтобы позволить 1-м и сторонним разработчикам создавать на основе .NET Core и выполнять переносимость без изменений на .NET Framework. Добавление элементов в интерфейсы нарушает это, поскольку потребители этих элементов не работают, когда они работают в .NET Framework.

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

Подводя итог обсуждению, причина, по которой вы считаете, что Microsoft должна портировать эти интерфейсы, состоит в том, чтобы позволить экосистеме легко переноситься на .NET Core, сохраняя при этом свои реализации .NET Framework?

состоит в том, чтобы позволить экосистеме легко переноситься на .NET Core, сохраняя при этом свои реализации .NET Framework?

да.

Подводя итог обсуждению, причина, по которой вы считаете, что Microsoft должна портировать эти интерфейсы, состоит в том, чтобы позволить экосистеме легко переноситься на .NET Core, сохраняя при этом свои реализации .NET Framework?

да. Внешние API теперь не работают, если я портирую свою кодовую базу (LLBLGen Pro) на corefx: тогда мне нужно открыть 2 API или сломать существующую кодовую базу для всех моих пользователей.

Возможно, вы, люди, сломаете наши вещи, потому что вы не чувствуете боли, а мы. Меня это не устраивает: я должен либо жить с убитой базой кода и поддерживать 2 API, которые делают то же самое, ЛИБО нарушать код моих пользователей, потому что вы думали, что это нормально.

Я также не понимаю, почему интерфейсы не версируются, это просто интерфейс, как и у класса тоже есть интерфейс. CoreFX прекрасно может добавлять асинхронные методы к интерфейсам.

Поверхность .NET Core должна быть бинарно совместимой с .NET Framework, чтобы позволить 1-м и сторонним разработчикам создавать на основе .NET Core и выполнять переносимость без изменений на .NET Framework. Добавление элементов в интерфейсы нарушает это, поскольку потребители этих элементов не работают, когда они работают в .NET Framework.

Простое решение: добавьте интерфейсы в том виде, в каком они есть сейчас. И как только вы все поймете, что это правило, приведенное выше, на самом деле довольно глупо, вы можете добавить к интерфейсам методы, которые вам нужно было давно добавить к интерфейсам, и двигаться дальше.

Я работаю с программным обеспечением MS достаточно долго, так что правила, подобные приведенным выше, хороши на бумаге, но на практике нарушаются, когда важная команда MS требует их нарушения. Если вы настолько «открыты» и «непохожи», как вы говорите в маркетинговой рекламе CoreFX, покажите это. Все, что я вижу в отношении System.Data и CoreFX, - это «то, что нужно MS, сделано, а то, что нужно всем, остается в стороне или игнорируется».

Я забыл упомянуть еще одну вещь: вчера Фаулер упомянул в Твиттере, что вам нужно, чтобы все портировали свои материалы. Я должен сам заплатить за перенос 500K кодовой базы LoC на CoreFX, это требует времени, усилий и времени на другие функции. Дополнительное трение, которое является полностью искусственным (это новая платформа! Как могут быть ограничительные правила?), На самом деле совсем не помогает: оно увеличивает затраты на обслуживание, требует дополнительного времени для переноса кода и тестирования и создает дополнительную нагрузку для наших пользователей.

Все это выходит за рамки вашей компетенции, и, похоже, это не ваша забота. Но вы забываете одну вещь: что _ если_ мы не портируем наш код и со мной больше людей? Я готов потратить время и, следовательно, свои собственные деньги, чтобы перенести свою большую кодовую базу на ваш новый блестящий фреймворк, но извините за это, всякий раз, когда я сталкиваюсь с проблемой, я сталкиваюсь с ограничениями, странными правилами и бесконечными дебатами, заканчивающимися тишиной . Айоу: Я чувствую себя совершенно одиноким, и в то же время вы, кажется, отчаянно хотите, чтобы нам понравился ваш новый блестящий фреймворк.

Как я сказал давным-давно : продайте мне этот фреймворк, этот новый CoreFX. Что ж, поддержание трения и добавление большого количества перемещенного и убранного сыра не создает большого стимула вкладывать в это большое количество времени (и денег).

Только мои 2центы.

@FransBouma Давайте постараемся, чтобы этот разговор был профессиональным, продуктивным и сосредоточенным на фактах.

Я не выступаю за или против добавления интерфейсов. Однако добавление методов к интерфейсам несовместимо. Давайте пройдемся по этому:

1) Добавьте IDbConnection.OpenAsync в .NET Core
2) Любой, кто вызовет этот метод, теперь не сможет работать в .NET Framework (нарушая основной принцип / цель, которые я назвал выше). Это также нарушает работу конструктора XAML и некоторых других функций VS, которые полагаются на этот факт.
3) Чтобы обновить .NET Framework, мы поставляем новую версию .NET Framework 4.7 с IDbConnection.OpenAsync.
4) Каждый отдельный тип, который реализовал IDbConnection до добавления этого метода, теперь не может загружаться в .NET Framework "4.7".

Вот почему мы не можем добавлять методы в интерфейсы.

Если я сохраню разочарование по поводу того, как обстоят дела с сообщением о проблемах с РС самому себе, вы все не узнаете об этом и подумаете, что все - розы и радуги. Если это выглядит непрофессионально, да ладно, меня не волнует, считает ли MS, что я профессионал или нет.

Тем не менее: я не женат на интерфейсах, поэтому, если они исчезнут, тот факт, что с тех пор есть классы и нет интерфейсов для работы в теории, не сделает меня грустной пандой: то, что должно быть сделано, может Теоретически это можно сделать и с помощью базовых классов, сегодня, поскольку сегодня все основные провайдеры ADO.NET работают хорошо и наследуются от базовых классов (в прошлом IIRC с ODP.NET реализовал интерфейс, но не происходит от базового класса). Это также причина, по которой я изначально не думал, что их удаление было большим делом. С тех пор у меня было время подумать об этом, и я думаю, что это очень важно.

Мы не живем в вакууме на Марсе, и промежуточное ПО / фреймворки в нижней части стека теперь имеют проблему: пользователи текущих полных версий .NET этих фреймворков хотят продолжать использовать их в CoreFX, поскольку они знают эти фреймворки. Однако перенос их на CoreFX - это большая PITA из-за множества причин, одна из которых - часто используемые интерфейсы, представленные в общедоступных API, не присутствующих в CoreFX (и причина этого потока).

Только по этой причине я хотел бы снова увидеть интерфейсы. Лично для меня не по техническим причинам (например, async нужны базовые классы, это уже беспорядок). Я знаю, что им не хватает определенных методов, но это ваша проблема, а не моя. Их удаление делает это моей проблемой и (перефразируя сейчас) ответом MS на это: поднимите руки со словами «не может быть сделано!». Но у меня нет такой роскоши. Вы создали этот беспорядок, вы его решаете. Вы хотите, чтобы я портировал свой код, вкладывал много времени и денег (которые я должен был заплатить за себя) в поддержку вашей новой структуры, почему вы тогда делаете _your_ проблему _my_ проблемой?

Рассмотрим ваш четырехэтапный сценарий: добавление методов в интерфейсы не проблема, ЕСЛИ вы видите CoreFX как отдельную платформу. И разве это не так? Это то же самое, что и с Compact Framework все эти годы назад (на который я перенес свой фреймворк, и тогда я извлек пару жестких уроков, которые говорят мне, что перенос на CoreFX не будет простым, быстрым и легким и сохранит две базы кода). тоже не будет): мы начинаем с 1 API, затем кто-то что-то забыл или какой-то команде в MS что-то нужно, и, несмотря на критическое изменение, столкнутся только несколько разработчиков низкоуровневого стека и так далее, и две дороги разделятся.

(пример: Compact Framework забыл 'SerializableAttribute'. Они добавили это с фиктивным атрибутом, который ничего не делал в более поздней версии, но это нарушило код, который ожидал того, что он отсутствовал и который определил свой собственный)

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

Восприятие вещей как «совместимых» важно не только на уровне подписи API, но и на уровне _behavior_ API. Вера в то, что эти два будут полностью одинаковыми (CoreFX и .NET Full) в поведении API, слишком рискованна: разработчик фреймворка должен будет протестировать одну и ту же функциональность на CoreFX и на .NET full, тестирование только на CoreFX невозможно. достаточно, чтобы предположить, что в будущем код будет работать на 100% точно так же в .NET, потому что как вы можете гарантировать это? Стек вызовов 20 глубоких вызовов CoreFX затронул так много другого кода, чем полный .NET, мелкие детали здесь и там, и все меняется.

Суть всего в том, что это отдельная структура: можно ожидать, что код, скомпилированный с использованием CoreFX, будет отличаться от кода, скомпилированного с использованием .NET full.

Есть несколько ситуаций:

1) фреймворк имеет кодовую базу, 100% которой компилируется на CoreFX. Это дает dll, которая запускается на .NET full
2) фреймворк имеет кодовую базу, 70% которой компилируется на CoreFX, а 100% - на .NET. Это дает 2 библиотеки DLL: одну для CoreFX и одну для .NET full. Глупо запускать версию CoreFX на .NET в полном объеме, так как упускается 30% функциональности.

В случае 1) я понимаю вашу точку зрения. В случае 2) (что относится ко всем текущим фреймворкам полного таргетинга .NET, среди них _все_ сторонние ORM) ваша точка зрения действительно бессмысленна, так как им все равно придется работать с 2 DLL: фактически 2 базы кода, которые должны обслуживаться отдельно, отдельно тестироваться и отдельно переноситься на новые версии. Особенно, если CoreFX получит новые функции, которые еще не являются частью .NET full (что будет). (Кстати: если вы добавите DbDataReader.GetSchemaTable () в CoreFX, который возвращает другую структуру данных, чем DataTable, потому что MS отказывается переносить это, код, использующий DbDataReader.GetSchemaTable на CoreFX, также сломается на .NET full. Если вы назовете его по-другому он сломается, так же как и метода там нет. Айоу: код сломается, если используются вещи, которых нет в _both_ фреймворках. Это не значит, что чего-то не должно быть в CoreFX).

Отсутствие интерфейсов в CoreFX делает ситуацию фреймворка в ситуации 2) постоянной: они не могут двигаться, чтобы стать фреймворком, который подходит для 1), потому что, например, их API предоставляет интерфейсы.

Microsoft переписывает свои собственные вещи, чтобы их фреймворки стали фреймворками в ситуации 1) - это круто, однако у нас нет бюджета в миллион долларов, 15+ человек в среде выполнения ORM и большой PR-машина на нашей стороне, которая сгладит морщины ломать все приложения. Таким образом, мы либо застряли в 2), либо нуждаемся в небольшой помощи со стороны MS, чтобы перейти к 1).

Вот что здесь поставлено на карту. Вы сказали в твиттере: «Расскажите, что вам нужно». Мы сделали. Неоднократно. Особенно в отношении System.Data связи нет . Ничего такого. Никаких планов на будущее, никаких обсуждений, что делать, только тупики, а иногда, если в дело вмешивается человек с РС, это тот, кто не имеет реальной заинтересованности в этом вопросе. Я ценю ваше время, потраченное на это, чем больше у нас опыта, тем лучше, но в то же время это похоже на разговор об этом с коллегой: проблема не будет решена, потому что ответственные лица отсутствуют и не участие в обсуждении.

Если это меня расстраивает и не дай бог «непрофессионально», то пусть так.

Спасибо за внимание. Между прочим, у меня нет иллюзий по поводу System.Data: это будет крушение API для переноса кода, и, поскольку нет связи между людьми, отвечающими с разработчиками, которые пишут ключевые фреймворки поверх своего API, почти нет надежды изменится. Не твоя вина, @davkean , ничего личного.

Я должен повторить разочарование, о котором говорилось выше, по поводу отсутствия общения. Нам также нужны массовые вставки и информация о схеме. За месяц (см. Dotnet / runtime # 15269 и dotnet / runtime # 14302) не было никаких улучшений или сообщений об этих недостающих основных (в обоих направлениях) функциях. Тем не менее, Microsoft маркирует текущий код как «кандидат на выпуск», что само по себе является сигналом «он достаточно хорош». Это не. Отсутствуют основные вещи, которые необходимо добавить, и, если вы будете следовать этим потокам, должны быть в первой версии по аналогичным причинам управления версиями.

Посмотрите на последнее обновление в dotnet / runtime # 14302 («Почему DataTable / View / Set отсутствует?»), Оно от 22 дней назад спрашивает:

Итак, System.Data.Common - это завершенная функция для V1 CoreCLR?

Да, разочарование может показаться непрофессиональным. Тон и контекст текста - отстой, и всегда так было, но мы ограничены этим здесь. Я думаю, что здесь все стараются быть продуктивными, но мы получаем довольно много препятствий со стороны CoreFX в отношении фактического прогресса в области System.Data что, откровенно говоря, приводит в ярость как автора библиотеки и пользователь этих битов.

Нам нужны эти основные функциональные элементы, интерфейсы или нет - я не особо разбираюсь в интерфейсах, и мы портировали Dapper без них. Но отсутствие DataTable, информации о схеме результатов, массовая вставка и т. Д. Недопустимы в «кандидате на выпуск». Microsoft - одна из тех, кто увеличивает разочарование в связи с маркировкой текущего кода как RC, когда почти все согласны с тем, что он не готов к выпуску. Да, это просто ярлык, но это и неправильный ярлык, и тот, который резко увеличивает уровень срочности, потому что он основан на произвольном графике (который должен был измениться, чтобы отразить реальность). Я не думаю, что кто-то в этой теме несет ответственность за это расписание, но это стоит указать как главный фактор в _уровне_ разочарования.

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

Не забываем про NHibernate с более чем 1 млн загрузок :

| IDbConnection | IDbCommand | IDataReader |
| --- | --- | --- |
| 59 | 181 | 132 |

Текущее мнение таково, что ADO.NET/CoreCLR перепроектируется, чтобы обеспечить первоклассную поддержку EF и SQL Server, при этом остальная часть экосистемы игнорируется - непрозрачные критические решения, подобные этому, только усиливают этот стереотип. .

Это восприятие подкрепляется такими вещами: https://github.com/dotnet/corefx/issues/4646

Насколько я могу судить, есть нулевой способ реализации этого API в любом полезном пути наружу из SqlClient сборки.

В настоящее время я нормально тестирую без интерфейсов. Но, честно говоря, я не понимаю, что такое управление версиями интерфейса и совместимость.

Разве идея .NET Core не в том, что это новая структура без бремени совместимости и что она связана с вашим приложением, так что вам не нужно иметь дело с подобными проблемами? Поставщик уже несовместим с поставщиками в .NET из-за отсутствия таких вещей, как схемы и таблицы данных, так что же может нарушить совместимость? Если интерфейс изменится, просто скомпилируйте новую версию и свяжите ее со своим приложением.

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

Для тех, кто намеревается поддерживать несколько фреймворков и исторически ориентировался на интерфейсы ... Я просто хочу поделиться кучей уродливых, которые использует Dapper; Я не говорю, что это _хорошо_, но этого достаточно для компиляции. Конечно, это дублируется в огромной куче файлов ... Я в основном делюсь этим, чтобы подчеркнуть еще одно влияние:

https://github.com/StackExchange/dapper-dot-net/blob/master/Dapper/SqlMapper.cs#L6 -L16

Мы не можем добавлять участников в интерфейсы

Правильно, и это _хорошая_ особенность интерфейсов. Предпочтение абстрактных базовых классов - это самый безопасный способ помочь энтропии API, а не бороться с ней.

Хотя вам не _обязательно_ следовать принципам OOD , я бы посоветовал вам это делать при создании OO API. Короче говоря, Принцип разделения

Если вы добавляете новые методы к существующей абстракции, вы автоматически нарушаете ISP.

Вы можете решить, что вам «не нужно придерживаться SOLID», потому что вы Microsoft и работаете с BCL, поэтому «обычные правила не применяются» (не настоящие кавычки; просто перефразируя обычные контраргументы).

Я поддерживал пару проектов с открытым исходным кодом в течение 6-7 лет, и по моему опыту лучше, чтобы интерфейсы были небольшими. Если вам нужно добавить новые возможности в абстракцию, представьте новый интерфейс.

Если бы здесь были голоса за, я бы поддержал комментарий

Как обычно, проницательный комментарий от @ploeh .

@FransBouma , мы добавим заменяющую функцию DbDataReader.GetSchemaTable () таким образом, чтобы это не нарушило всю структуру.
@NickCraver , SqlBulkCopy входит в наши планы на будущее, и мы работаем над схемой. Мы медленно продвигаемся по схеме, так как нам также необходимо добиться разумного прогресса в том, чтобы наш стек работал на x-платформе.
@mythz , спасибо за примеры, цифры и оценку воздействия на клиентов. Мы их рассмотрим.

@YoungGah Пожалуйста, обновляйте проблемы, связанные с информацией, чтобы они оставались актуальными, например https://github.com/dotnet/corefx/issues/1039 , иначе скудная информация будет разбросана повсюду. Приятно, что вы добавите GetSchemaTable (и эквивалент DbConnection, не забывайте об этом!), Но так сложно получить какую-либо информацию о том, что произойдет и _ когда_. Есть какой-нибудь план, что и когда будет добавлено? Все, что нам нужно сделать сейчас, это намек на то, что «в будущем» что-то может быть добавлено. Честно говоря, это не очень хорошо для планирования порта базы кода.

@FransBouma , да, я

Что здесь происходит, и на будущее @YoungGah; IDataReader зависит от DataTable, который зависит от DataSet (который мы рассматриваем как отдельный уровень - потому что это тяжелая политика, в отличие от этих типов, которые не содержат политик), поэтому здесь есть некоторая дизайнерская работа, чтобы сломать это, если бы эти интерфейсы когда-либо были вернул.

Я бы поставил здесь другое голосование за @davkean по разделению, так и управления версиями.

Почему у вас просто не может быть новый интерфейс, наследующий старый? Устаревший старый. Удалите старую в будущем. По крайней мере, тогда вы можете расширить его и не нарушить существующие способы использования.

Или несколько меньших интерфейсов. Я просто получил плохой комментарий.

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

Когда я предлагал интерфейсы обратно, я не думал о том, чтобы вернуть оригинальные интерфейсы 1.1, но обновил интерфейсы с новым дизайном. Как сказал

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

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

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

Итак, прекрасная возможность избавиться от исходных плохо спроектированных интерфейсов и стандартизировать базовые классы, такие как ADO.NET, уже делает? :Тролль:

А если серьезно, у вас есть выбор между чистым API или обратной совместимостью. Выбери один. Я не вижу способа съесть твой торт и тоже его съесть.

@JamesNK, но в том-то и дело. Обратная совместимость не требуется, точка.

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

ADO.NET - один из самых стабильных фрагментов кода во всем .NET. За 15 лет произошло два-три серьезных изменения. Это идеальный API для стабилизации интерфейса и упрощения его работы для всех.

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

@nvivo Должен признаться, я запутался. После того, как мы установили, что базовые классы обеспечивают возможность тестирования, этот поток трансформировался в возвращение интерфейсов, позволяющих переносить код .NET Framework на .NET Core. Как этому помогает редизайн интерфейсов и введение чего-то нового?

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

@davkean

Я не могу ответить за всех, кто здесь комментировал. Я предложил использовать интерфейсы в качестве API ADO.NET, обновленного до нового текущего API. Я не просил принести оригинальные интерфейсы и все проблемы с ними. Цель заключалась в том, чтобы иметь более чистый определенный API и упростить имитацию и тестирование кода, который от него зависит, в основном библиотеки абстракции данных, а не пользовательский код.

Интерфейсы лучше описывают API, как мудро сказал @ploeh , и их намного проще высмеивать. Текущий дизайн ужасен для насмешек и требует, чтобы вы реализовали почти весь поставщик в виде библиотеки для выполнения простых тестов. Если это не для всех важно, я могу понять. Но я определенно не согласен с тем, что сегодня это достаточно проверено. Проверка того, был ли вызван метод A с параметром X, путем проверки того, что метод B, вызванный C с параметрами X, Y, Z, не идеален.

Теперь просто чтобы увидеть, как классы уже создают плохой дизайн:

  • Почему у DbCommand есть свойство DesignTimeVisible ? Поддерживает ли время разработки требование, чтобы соединение определялось как соединение?
  • Почему существует событие для уведомления об изменении состояния, но не для уведомления о других вещах, например о выполненных командах или запуске транзакций? Является ли уведомление даже требованием для существования соединений или чем-то, что упрощает создание пользовательского интерфейса?
  • Является ли ConnectionStringBuilder требованием для существования поставщика? Или еще лучше заставить мастеров VS работать из коробки?
  • Почему DbDataReader определяет методы Get для некоторых основных типов, но не добавляет для других, таких как GetByteArray() и GetDateTimeOffset() ? И даже требуется ли извлечение TextReader, если это можно сделать вне с помощью строк или потоков? Если бы это был интерфейс, были бы такие методы добавлены в API или созданы как методы расширения или помощники в конкретных классах (например, семейство GetSql* в SqlDataReader)?

Все это вопросы риторические. Я уверен, что на все они есть убедительные ответы, и все они были учтены. Дело в том, что текущий дизайн явно не является чем-то, что рассматривалось как определение API , что, вероятно, привлекло бы больше внимания с интерфейсами.

Честно говоря, со стороны обсуждение дизайна звучит так:

  • давайте оставим эти события здесь, потому что мастерам в Visual Studio проще работать из коробки
  • давайте удалим методы получения схемы, потому что у нас есть EF, и это то, что должны использовать все в мире, точка.
  • давайте оставим эти удобные методы, потому что они поддерживаются начиная с .NET 1.1, и мы НИКОГДА не можем нарушить совместимость!
  • давайте удалим таблицы и наборы данных и все равно заставим всех, кто работает с .NET 1.1, изменить всю свою кодовую базу!
  • давайте построим новую модель поставщика, ориентированную на облачные вычисления, сообщество, открытый исходный код и приложения завтрашнего дня ...
  • ... и давайте построим эту модель на основе вчерашних потребностей, используя SqlClient в качестве _sole_ тестового примера!
  • давайте создадим совершенно новый фреймворк, который будет связан с каждым приложением, чтобы никому не приходилось беспокоиться об обновлениях, нарушающих работу их приложения - никогда снова!
  • ... тогда давайте примем решение не добавлять интерфейсы, потому что любые изменения могут нарушить их обновления!

Да, там немного разглагольствования и это обсуждение ни к чему не приведет =) ... Но просто хотел вытащить это из моей груди. 2015 год, все время ломается и мы к этому привыкли. В ближайшие годы будет 20 обновлений ASP.NET MVC, которые вызовут гораздо больше критических изменений, чем изменения интерфейса в ADO.NET.

Я по-прежнему люблю .NET и то, что вы с ним делаете в целом, я уверен, что это спешка, чтобы вовремя выпустить .NET Core v1, и не все будет идеально. Я просто надеюсь, что сообщество может помочь направить это в другие направления со временем, и вы не боитесь ломать вещи по мере нашего продвижения.

Для разработчиков ORM: почему бы не сделать

`` С #

если COREFX

namespace System.Data {
общедоступный интерфейс IDbConnection {...}
}
`` ''

и использовать шаблон адаптера, чтобы обернуть новый System.Data своими собственными реализациями? Фактически, вы можете создать для него пакет с открытым исходным кодом и поделиться им.

It's 2015, everything breaks all the time and we're used to it. There will be 20 updates to ASP.NET MVC in the next years that will cause a lot more breaking changes than interface changes in ADO.NET.

I still love .NET and what you're doing with it in general, I'm sure it's a rush to get .NET Core v1 out in time and not everything will be perfect. I just hope the community can help steer this to other directions as the time goes and you're not afraid to break things as we move.
- nvivo

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

@thefringeninja, который либо добавляет совершенно ненужную и extern alias для удаления (и много путаницы, почему метод, который принимает System.Data.IDbConnection не примет разные, но одинаковые System.Data.IDbConnection которые вы ему предлагаете). По сути, это сделало бы ситуацию в 10 раз хуже.

Можете привести конкретный пример @mgravell ? Я вижу, как это могло бы сломаться, если бы вы использовали Type.GetType("System.Data.IDbConnection, System.Data") или, может быть, в сценариях PCL.

Если orm A определяет System.Data.IDbConnection, а orm B определяет
System.Data.IDbConnection, то теперь есть два совершенно разных и
несовместимые интерфейсы с одинаковым именем / пространством имен, конфликтом и
на самом деле не работают ни с одним из поставщиков БД. Ничего не решает,
по сути. Хуже того: они сдаются в аренду непригодным для использования API, где кто-то ожидает передать
в SqlConnection или NgpSqlConnection - и это не работает.

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

Если это не System.Data.Common, это означает, что DbConnection не реализует его, и: вы можете не беспокоиться.

Вы никогда не получите консенсуса для каждого сопровождающего провайдера ORM или ADO .NET, чтобы он взял на себя внешнюю зависимость от сторонних производителей (в значительной степени гарантирует, что SQL Server не будет), и две библиотеки, переопределяющие базовый интерфейс BCL, не могут использоваться вместе. Что еще хуже, для высокоуровневых фреймворков (таких как ServiceStack), которые ссылаются на интерфейсы System.Data в основных библиотеках (которые теперь необходимо определить), больше не будет возможности использовать ORM, который не ссылается на те же интерфейсы, что не -Один был бы или должен.

Единственный способ убедиться, что каждая библиотека ссылается на одни и те же интерфейсы System.Data, - это если они были восстановлены с помощью базовых классов, реализующих их, - что я до сих пор не понимаю, какой вред это имеет.

@mgravell ах транзитивная зависимость, не

Вы знаете, я не понимаю, почему это проблема, если вы не связали свой код с кодом, которым вы не владеете. Защитите свой код от зависимостей! Оберните его и абстрагируйте. Есть много способов сделать это и сделать ваш код тестируемым. Многие упомянуты выше. Вы интегрируете те биты, которыми не владеете. Вот как это работает. Вы не должны издеваться над объектами BCL! Если да, то ваш дизайн плохой.

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

@mythz С интерфейсами у нас возникли две проблемы; 1) они привнесли (тяжелую) зависимость от DataSet, которая не относится к абстракциям без политик, и 2) они привносят параллельный набор абстракций в базовые классы, но заблокированы областью поверхности v1. Мы хотели избежать этой путаницы.

Я согласен, что предоставление этих интерфейсов третьим лицам нецелесообразно - они должны быть реализованы в основных абстракциях, чтобы быть полезными.

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

В этом нет абсолютно никакого смысла.

@nvivo это означает, что

2015 год, все время ломается и мы к этому привыкли.

Но это не удовлетворительная стратегия для тех из нас, кто должен поддерживать существующие кодовые базы и кодовые базы нашего Заказчика, и определенно не должна быть стратегией по умолчанию для хранителей библиотек BCL, влияющих на всю .NET.

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

@mythz Это вне контекста. Это не то, что я имел ввиду. Здесь все должны поддерживать существующие базы кода, я сомневаюсь, что в обсуждении есть новичок в .NET.

Проблема в том, во что превратился этот разговор, в том, что он не имеет особого смысла. .NET Core - это новый фреймворк, а не обновление. Многие из существующих полных .NET API отсутствуют и не будут. В любом случае обратная совместимость так работать не будет.

@nvivo Именно из-за этого

Все эти разговоры о том, что интерфейсы несовместимы с версиями, заставляют меня задуматься о том, как язык программирования Go позволяет обойти эту проблему с помощью неявных интерфейсов.

Меня попросили расширить то, что я имел в виду под абстракциями _policy-free_.

По сути, под «свободными от политик» я подразумеваю, что абстракции System.Data.Common содержат почти ноль бизнес-правил - все, что они делают, это предоставляют форму API, которую данный провайдер должен реализовать. В этом отличие от DataSet, в котором есть множество бизнес-правил и кода. Типы, свободные от политик, в силу самой их конструкции, как правило, реже обновляются, чем типы, содержащие политику, поскольку там меньше кода, следовательно, меньше ошибок и изменений дизайна. Нам нужны абстракции и типы, которые _обмениваются_ [1] между сторонними библиотеками до версии нечасто [2], чтобы уменьшить количество проблем, с которыми вы сталкиваетесь при координации зависимостей в большом графе пакетов. Вы не можете встраивать или объединять типы обмена как часть вашего приложения, тогда как типы без обмена вы можете. Следовательно, почему мы хотим, чтобы они были разделены.

[1] Под _exchanged_ я имею в виду типы, которые обычно появляются в общедоступных API. Например, мы рассматриваем Collection<T> как тип обмена, но не List<T> .
[2] Использование семантического управления версиями для них привело бы к остановкам, почти таким же, как описано выше, с удаленными интерфейсами, потому что вы «разветвляете» экосистему; Библиотеки должны принять решение, использовать ли библиотеку как таргетинг до или после разрыва, или выполнить форк для обработки разделения.

@mythz Я должен поддерживать orms / customers как часть коммерческого приложения и существующего кода .... Я не говорю, что согласен с какой-либо из сторон, но факт в том, что dnx - это совершенно новая среда / среда выполнения. Если у него нет каких-либо интерфейсов, справьтесь с этим ... с помощью директивы компилятора.

Если у него нет каких-либо интерфейсов, справьтесь с этим ... с помощью директивы компилятора.

ой? как насчет метода, возвращающего IDataReader, или метода, принимающего IDbConnection? Или IDbTransaction? Как вы собираетесь решить эту проблему с помощью #ifdev, если ваш _customers_ код использует этот API?

«Разберись с этим» ... что это за высокомерие?

Просто обновите базовый пакет (вашу организацию), чтобы он возвращал ваш собственный тип или базовый тип, который они поддерживают с 2.0. Если вы ориентируетесь на более старые версии .net, вы можете использовать директиву, чтобы вместо этого вернуть интерфейс и пометить его как устаревший.

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

@FransBouma, он, вероятно, тоже выступает за сильное именование.

@FransBouma @ phillip-haydon может заняться вашим троллингом в других местах, вы не можете ожидать, что вы будете так себя вести, и люди будут воспринимать вас всерьез. Если у вас есть какие-либо сомнения, взгляните на мои проекты / проекты с открытым исходным кодом ... Мне придется с этим разобраться ... в любом случае ...

Для протокола, я против сильного наименования.

Смирись с этим...

И вы говорите, что я троллю?

« @FransBouma, он, вероятно, тоже выступает за сильное именование». не по теме и не очень помогает в этом разговоре. Да похоже на твой троллинг ..

Один важный факт, который следует учитывать в этом обсуждении, заключается в том, что интерфейсы IDb * были объявлены устаревшими как API для ADO.NET в .NET 2.0 десять лет назад, когда были представлены базовые классы. Они не были помечены как устаревшие, но все, что было создано с тех пор, зависит от базовых классов. На ум приходят провайдеры App.config и поддержка строки подключения.

Если у вас есть код, зависящий от этих интерфейсов, вы кодируете очень устаревший API без поддержки таких вещей, как асинхронные методы, а это означает, что вам все равно нужно обновить его, если вы хотите, чтобы люди продолжали его использовать.

Просто обновите базовый пакет (вашу организацию), чтобы он возвращал ваш собственный тип или базовый тип, который они поддерживают с 2.0. Если вы ориентируетесь на более старые версии .net, вы можете использовать директиву, чтобы вместо этого вернуть интерфейс и пометить его как устаревший.

Это общедоступный API, используемый многими тысячами приложений, и этот API стал общедоступным и используется с .net 1.0. Напротив, это не «просто». Мы не можем просто изменить API, потому что Microsoft считает, что это то, что они должны сделать, чтобы сделать нашу жизнь лучше: это станет большим бременем для наших пользователей и, следовательно, для нас.

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

вот в чем дело: это не рассматривается как «новая среда выполнения». Если бы это было так, как я уже обсуждал, это не было бы проблемой. Однако Microsoft считает, что библиотеки для таргетинга CoreFX должны полностью работать и на .NET, поэтому новой структуры нет. Сопровождающим библиотеки, ориентированные на .NET full, с функциональностью не в CoreFX (так что многие библиотеки, существующие сегодня) ждут много «веселья», так как им придется поддерживать 2 версии. Не 2 или 3 #ifdev и проблема решена, а их очень много. Возможно, для вас все по-другому, поскольку вы, возможно, можете выставить счет своему клиенту за часы, которые вы потратите на изменение API. Другое дело, когда вы создаете систему общего назначения, которую используют многие.

Если поддержка компактного фреймворка - это какой-либо ориентир, поддержка ORM в полной .net и CoreCLR будет ужасной потерей времени, большим разочарованием и на самом деле не очень много: вы не получите новых функций, вы будете работать только с их _ отсутствием_ .

(и прежде, чем кто-то начнет с: «но он работает на linux, вы получите это»: наш материал работает на Mono уже много лет. Так что нет, это не совсем новая функция, которую можно получить, она уже была там).

SellMeThisFramework. О, почему я вообще беспокоюсь.

но все, что построено с тех пор, зависит от базовых классов.

_cough_ Linq-to-SQL DataContext _cough_

Как и многие ORM, не относящиеся к MS, отсюда и проблема. Для щеголя мы просто укусили
пуля и перешел на DbConnection. Если бы у нас было время снова, я
настоятельно рекомендую MS использовать [Obsolete], когда они что-то устаревают. Но:
мы не можем изменить прошлое.

Это очень болезненная проблема для решения, тем более что большинство
авторам библиотеки необходимо продолжить работу с обоими API (компиляция для
net40 и т. д., и другой способ для DNX). Я ранее публиковал ужасный беспорядок
этот dapper использует для этого: это некрасиво и не так просто, как

если.

27 ноября 2015 года в 20:07 "Natan Vivo" [email protected] написал:

Один важный факт, который следует учитывать в этом обсуждении, заключается в том, что IDb *
интерфейсы были объявлены устаревшими как API для ADO.NET в .NET 2.0 десять лет назад.
когда были введены базовые классы. Они не были помечены как устаревшие, но
все, что построено с тех пор, зависит от базовых классов.
На ум приходят провайдеры App.config и поддержка строки подключения.

Если у вас есть код, зависящий от этих интерфейсов, вы кодируете против
очень устаревший API без поддержки таких вещей, как асинхронные методы, что означает
вам все равно придется обновить его, если вы хотите, чтобы люди продолжали его использовать.

-
Ответьте на это письмо напрямую или просмотрите его на GitHub
https://github.com/dotnet/corefx/issues/3480#issuecomment -160198453.

Я не вижу смысла в том, что асинхронные методы не могут быть добавлены в результате использования интерфейсов. Вы могли бы создать новые интерфейсы для асинхронных методов. IAsyncDbCommand , IAsyncDataReader и т. Д. Тогда вы можете заставить базовые классы реализовывать оба типа интерфейсов.

Пользователи ADO.NET используют либо асинхронную версию, либо синхронную версию, но не обе одновременно. Так что это сработало бы просто отлично.

Для разработчиков библиотек не имеет значения, растет ли функциональность, а интерфейсы остаются прежними. Разве это не цель? Внедряйте новые интерфейсы для новых функций. Работа с базовыми классами - это просто боль.

Могу я просто резюмировать эту ветку здесь?

Несколько независимых признанных экспертов сообщества по инструментам .NET для работы с данными,
в том числе несколько авторов и разработчиков ORM говорят вам - вполне
ясно - что это представляет собой значительный набор проблем. Я не думаю
любой из нас не разбирается в тонкостях или наивен в программировании
принципы, и большинство из нас, если не все, прекрасно знают предысторию,
потому что мы были там в то время.

Официальный ответ, похоже, такой: «Нам это кажется нормальным, и EF довольна».
Да, мы это знаем, потому что решение было принято изначально.

Что ж, мы все высказали свое мнение, даже если оно не было плодотворным.
27 ноября 2015 г., 20:41, «Джонас Гауффин» [email protected] написал:

Я не вижу смысла в том, что асинхронные методы нельзя добавить как
результат использования интерфейсов. Вы могли бы создать _новые_ интерфейсы для
асинхронные методы. IAsyncDbCommand, IAsyncDataReader и т. Д. Тогда вы могли бы
сделать так, чтобы базовые классы реализовывали оба типа интерфейсов.

Пользователи ADO.NET используют либо асинхронную версию, либо синхронную версию.
версии, а не обе. Так что это сработало бы просто отлично.

Для разработчиков библиотек не имеет значения, растет ли функциональность и
интерфейсы остались прежними. Разве это не цель? Ввести новые
интерфейсы для новой функциональности. Работа с базовыми классами - это просто боль.

-
Ответьте на это письмо напрямую или просмотрите его на GitHub
https://github.com/dotnet/corefx/issues/3480#issuecomment -160201361.

Чуваки .. обновите свой код и увеличьте свою основную версию. Выполнено.

Да, но нет причин, по которым вы не можете заполнить этот интерфейс директивой компилятора при нацеливании на ядро. Я сделал это с некоторыми из наших пакетов pcl.

Я действительно думаю, что Microsoft нужно повторить, что ядро ​​не заполнено dot net, но это все равно не помогает ... Я думаю, что Microsoft нужно очистить некоторые интерфейсы, если честно. Недавно в блоге появилось сообщение, в котором есть очень несовместимые интерфейсы, и вы никогда не знаете, какой из них выбрать ... Я думаю, что определение второго асинхронного интерфейса - отстой. Было бы неплохо, если бы все было асинхронно ..

Было бы неплохо, если бы весь фреймворк прошел, чтобы убедиться, что вещи, которые нужно пометить как устаревшие, были ... И выпущены как 4.6.2

@mgravell +100. Хорошо сказано, согласен на 100%.

Насколько это действительно затронуто? Мы говорим здесь о coreclr? Рабочий стол .NET будет жить еще много лет, пока coreclr не догонит его. Именно для тех, кто жалуется, что вы здесь потеряете? Многие люди в основном говорят, что это конец света.

@leppie Действительно, он будет существовать много лет. И нам придется поддерживать эти приемы и обходные пути в нашем коде еще долгие годы. Предметом разногласий здесь является устранение общего моста между ними. Эта рабочая нагрузка была перенесена на всех разработчиков библиотек, а не на BCL. Я понимаю плюсы и минусы интерфейса с обеих сторон, но не понимаю, как некоторые здесь говорят «это второстепенно, двигайтесь дальше».

Давайте будем откровенны: если все потребители библиотеки должны делать одно и то же, это должно быть в BCL . Спор идет о том, "какую форму это принимает?"

Положительным моментом удаления интерфейсов является наличие _дополнительного_ механизма управления версиями с новой моделью упаковки: классы, доступные в X, Y и Z, теперь намного лучше поддерживаются инструментами. Например, dotnet5.2 против 5.4 в настоящее время. Но есть и недостатки. Например, SqlClient все еще не доходит до реализации интерфейсов в том виде, в каком он есть сегодня (см. Dotnet / runtime # 14302 и dotnet / runtime # 15269), и, учитывая то, что сказал @YoungGah (если я не неправильно понимаю), мы ждем на 5.4 или 5.5 для того же уровня поддержки схемы, массовых вставок и т. д.

Так что же происходит с 5.6 (1.5)? Если к абстрактным классам будет добавлено больше членов, ожидается, что каждый поставщик данных будет идти в ногу с движущейся целью, которая может меняться с каждым движущимся человеком? Каждому потребителю необходимо определить версию функций, доступных в каждом? Нам нужно скомпилировать версию сборки для каждой продвигающейся версии платформы, чтобы она соответствовала абстрактной базе передаваемого класса? Как все это работает с дополнениями, не на 100% ясно. Интерфейс, который не меняется, намного понятнее. Вдобавок к этому есть документация: какие функции, методы и т. Д. Доступны, в каких версиях _ и платформах_ будет огромной проблемой для всех авторов библиотек, продвигающихся вперед. Здесь это беспокойство лишь частично связано, но оно в игре.

А пока с нетерпением жду обновления в ближайшие 2 недели. Я опасаюсь, что это будет эффективно, как и все время обмен сообщениями: «Мы делаем X, потому что он работает для SQL и Entity Framework, и это достаточно хорошо» - без использования любого из этих слов. Для меня разочарование со стороны автора библиотеки заключалось в отсутствии прогресса (как в коде, так и в обсуждениях) на этих фронтах в течение нескольких месяцев.

100% согласен.

Когда я разработал версию 2 (и выше) SqlFu (мой Micro ORM), мне нужно было решить, где прикрепить методы расширения: к DbConnection / DbCommand или к интерфейсам. Я нашел это и решил перейти к абстрактным классам.

Таким образом, я не ТОЛЬКО затронут, хотя на меня влияет удаление IDataReader , потому что MS в своей мудрости решили не очень четко указывать, какие интерфейсы следует рассматривать как устаревшие, а какие нет. Но в моем случае заменить интерфейс несложно.

Тем не менее, я вижу ценность выделенных интерфейсов и не думаю, что для MS ТАК сложно сохранить / добавить их обратно. Если они решат, что старые интерфейсы не так хорошо спроектированы, хорошо! Создавайте новые, чтобы быть более конкретными. По крайней мере, в будущем нам не придется сталкиваться с той же проблемой.

(Это неделя Благодарения в США, поэтому ответы от Microsofties будут довольно ограниченными, пока они не вернутся в офис на следующей неделе)

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

@NickCraver Подобно совместимости версий .NET Framework, не будет никаких критических изменений между версиями

@davkean, насколько вы уверены, что этого не произойдет? Учитывая, что мы видим неполную площадь поверхности и нет никаких гарантий, что она изменится, трудно поверить, что недостающие части не появятся позже, если вообще не появятся. Тем не менее, я думаю, что отсутствие критических изменений - это _ более_ важная вещь, что, я уверен, большинство авторов библиотек здесь также предполагают. Это означает, что еще более важно позаботиться об этих элементах задолго до выхода RTM.

Для записи, что в поверхностной области были зарегистрированы отдельные проблемы, см. Dotnet / runtime # 14302 и dotnet / runtime # 15269 с последними обновлениями от Microsoft 25 сентября и 2 октября соответственно - несмотря на то, что после этого несколько раз запрашивали обновления и действия. Это 2 месяца и 2 релиза, которые вышли в тишине. И это несмотря на то, что dotnet / runtime # 14302 является наиболее активной проблемой в этом репо (а этот только что стал вторым). Вы понимаете наше разочарование?

Я абсолютно уверен, что мы не будем вносить критических изменений, команда Data Common собирается внести их без введения абстрактных участников.

@NickCraver Извините, у нас здесь плохо - эти проблемы не были забыты, @YoungGah предоставила информацию о них выше, я буду следить за тем, чтобы она обновляла проблемы по мере продвижения. Многие MS все еще привыкают к этой _работе в открытом режиме_, со временем она станет лучше - спасибо, что обратились к нам по этому поводу.

@niemyjski

dnx - это совершенно новый фреймворк / среда выполнения

Если вы думаете, что библиотеки dnx runtime и corefx возникли из воздуха, вы серьезно недооцениваете время, которое потребовалось бы для их разработки с нуля. Тот факт, что библиотеки CoreFx работают на полной платформе .NET Framework, должен дать вам понять, что нет, это не совсем что-то новое.

Если у него нет каких-либо интерфейсов, справьтесь с этим ... с помощью директивы компилятора.

Да, но нет причин, по которым вы не можете заполнить этот интерфейс директивой компилятора при нацеливании на ядро.

Если вы потрудились прочитать комментарии перед тем, как войти в эту ветку, вы знаете, что а) есть причины и б) это неработающая стратегия для основных интерфейсов BCL.

@nvivo

Один важный факт, который следует учитывать в этом обсуждении, заключается в том, что интерфейсы IDb * были объявлены устаревшими как API для ADO.NET в .NET 2.0 десять лет назад, когда были представлены базовые классы.

Если бы это было так, вы бы не открыли проблему, говоря им, чтобы они вернулись к использованию интерфейсов, которые, как вы сознательно знали, устарели базовыми классами десять лет назад. Способ сообщения API устарел - это использовать атрибут [Obsolete] который является его единственной целью для существования. Если это не широко распространено, оно не устарело, независимо от того, о чем вы сейчас думаете. Тот факт, что большинство ORM, не относящихся к MS .NET, полагаются на них, должен указывать на то, что об их устаревании было плохо сообщено, если вообще было.

Если у вас есть код, зависящий от этих интерфейсов, вы кодируете очень устаревший API без поддержки таких вещей, как асинхронные методы, а это означает, что вам все равно нужно обновить его, если вы хотите, чтобы люди продолжали его использовать.

Ложный соломенный человек - одно не подразумевает другого. Мы уже добавили поддержку асинхронных API-интерфейсов, и нет, их добавление не нарушило существующие клиентские базы кода и не изменило ни один из существующих API-интерфейсов.

Хорошо, все это - хорошее начало, но могу ли я задать один вопрос: какие компромиссы были приняты для поддержки ваших собственных фреймворков? Какие ужасы прошлого были перенесены, потому что они нужны, скажем, для запуска Entity Framework?

Было бы стыдно, если бы MicroORM исчезли, они делают код .Net несколько производительным (EF - непригодный зверь для приложений, где 500 мсек для загрузки нескольких строк неприемлемо).

Что касается интерфейсов и базовых классов: базовые классы великолепны, если все, что можно повторно использовать, является виртуальным. Например, одним из самых раздражающих дизайнерских решений в WCF является обильное использование запечатанных классов, которые содержат много функциональных возможностей. Скажем, вам нужно немного изменить способ обработки сообщений XML (потому что: interop). Вместо того, чтобы наследовать и переопределять одну небольшую функцию, вам придется заново реализовать. В примере с WCF буква S в SOLID была пропущена, поэтому обычно остается реализовать большой интерфейс без каких-либо тестов, необходимых для обеспечения его производственного качества.

Итак: базовые классы, которые мы можем адаптировать, - это хорошо.

Я абсолютно уверен, что мы не будем вносить критических изменений, команда Data Common собирается внести их без введения абстрактных участников.

@davkean Это невозможно гарантировать, и вы это знаете. ADO.NET - это подсистема для связи со сторонним программным обеспечением с широким спектром функций, которые доступны через общий API с некоторыми точками расширения. Вещи меняются даже в области баз данных, и эти изменения отражаются на API, используемом для связи и использования этих внешних служб баз данных. Кроме того: изменения в поведении также являются критическими изменениями. И мы видели это тоже в ADO.NET (например, об обработке ошибок) в последние годы.

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

Короче говоря, это API, который в начале .NET 1.0 имел общий дизайн (который, как оказалось, имел серьезные недостатки во многих областях) и который с тех пор был исправлен с помощью функций слева и справа, чтобы справиться с изменениями в пейзаж. _Большинство_ из них все еще находится в API (если не все). И теперь Microsoft уберет одно: интерфейсы.

Абсолютно ничего не выиграет от удаления случайной части API: никакая функция не добавляется через это (вы могли бы потратить на это время, вместо того, чтобы, например, возвращаться сюда), но код, который использует эту часть API, не будет работать. Если за всем этим движением сыра стоит `` начать все сначала '', то делайте это во что бы то ни стало, но сделайте это, изменив API, чтобы сделать его по-настоящему универсальным API, избавьтесь от всего мусора, накопившегося за эти годы. .

Но это еще не сделано. Никто не должен удивляться почему, мы все знаем почему. Мы также знаем, что если бы команда в MS сильно пострадала из-за удаления интерфейсов, они никогда бы не были удалены вообще.

Если Microsoft может добавить новые функции с помощью базовых классов, чтобы сторонние поставщики автоматически реализовали «форму» функции (например, с Async, где метод async возвращается к методу синхронизации, если поставщик не реализует его), отлично: это означает, что мы, сторонние разработчики ORM (и признаем это: многие разработчики получают доступ к _your_ API через код сторонних (микро) ORM), можем просто нацеливаться на один класс и все.

Но нет гарантии, что вы это сделаете. Например, никто в Microsoft никогда не озаботился добавлением конкретных функций Oracle или PostgreSql в ADO.NET. Например, использование UDT, деревьев документов, множественных наборов результатов с помощью курсоров, каждый провайдер ADO.NET должен найти свой собственный способ работы с этими функциями. Что, если (когда?) SQL Server получит функцию дерева документов, например, с документами JSON, будет ли ADO.NET обновлен с новым API для этого? Как вы поступали раньше с отчетами об ошибках от поставщиков ADO.NET?

Вы не можете дать таких гарантий, и неразумно заявлять здесь, что MS ничего не сломает в будущем. Так было всегда, а иногда даже приходилось: в конце концов, у каждого API есть недостатки, а в ADO.NET их полно; так или иначе, когда-нибудь кто-нибудь «исправит» их.

Итак, резюмируем: интерфейсы являются частью ADO.NET, так же как и испорченные части в другом месте API являются частью ADO.NET. Они не удаляются, чтобы исправить API, и API не подвергается рефакторингу, чтобы сделать его API более общего назначения: он был оставлен как есть, с некоторыми удаленными элементами, такими как элементы, зависящие от DataSet / Table, потому что они не портированы (и там другие проблемы, обсуждаемые с аналогичным прогрессом), за исключением того, что ... интерфейсы удалены.

Уже с этой точки зрения это не имеет никакого смысла.

@mythz

Если бы это было так, вы бы не открыли проблему, предлагая им вернуться к использованию интерфейсов, которые, как вы сознательно знали, устарели.

Вы не можете прочитать OP и понять это. Эти дискуссии становятся слишком религиозными, и вы просто предполагаете то, чего никто не говорил.

Я открыл эту проблему, потому что считаю, что интерфейсы лучше описывают api и помогают при тестировании. Если это будет сделано, я не думаю, что они должны быть совместимы с API 15-летней давности, у которого были свои проблемы. Обратная совместимость никогда не была предметом обсуждения, пока вы, ребята, не перешли к этому вопросу.

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

Мы уже добавили поддержку асинхронных API

Вы не можете добавить async api поверх sync api. Если вы сделали это с помощью IDbConnection или IDbCommand, вы сделали это неправильно. Если вы не используете эти интерфейсы, вам действительно нет смысла защищать с ними обратную совместимость.

Мы уже добавили поддержку асинхронных API

Вы не можете добавить async api поверх sync api. Если вы сделали это с помощью IDbConnection или IDbCommand, вы сделали это неправильно. Если вы не используете эти интерфейсы, вам действительно нет смысла защищать с ними обратную совместимость.

В ADO.NET они поступили именно так: методы Async по умолчанию возвращаются к вариантам синхронизации. Таким образом, всем поставщикам ADO.NET, которые не поддерживают Async (читайте: все они, кроме SqlServer на данный момент), не нужно реализовывать то, что они не поддерживают: сторонний код в ORM, предлагающий Async api, может программировать против методы Async в ADO.NET, и если провайдер ado.net не поддерживает асинхронность, на самом деле никто не узнает. Ну ... ты узнаешь, потому что он медленнее, но это в сторону.

Теперь это также хорошая иллюстрация отсутствия какого-либо «дизайна» или общей архитектуры в ADO.NET: _no_ способ создать точку сохранения транзакции в общем API. Хотя почти все базы данных поддерживают это с помощью метода «Сохранить (строка)» в своем производном классе от DbTransaction. Все, кроме OleDbTransaction (поскольку MS Access его не поддерживает, по крайней мере, это мое подозрение).

Это непросто, но никто не сказал, что это будет легко. Эта проблема не нова, OleDB и ODBC решали ее на протяжении многих лет, JDBC нашел способ ее решения, Microsoft не нужно заново изобретать колесо, чтобы преодолеть подобные вещи. Это также не уникально для области БД: например, каждая видеокарта поддерживает различные подмножества функций через свой API, предоставляемый разработчику через Direct3D / X. На самом деле интересно, как проектируются в этих других мирах: API разработан, и стороны, которым необходимо его поддерживать (драйверы JDBC, разработчики драйверов OleDB и т. Д.), Должны их реализовать. Ваш драйвер не поддерживает X? Ваш драйвер несовместим с X. «Oracle не поддерживает ADO.NET v10». Никто в Oracle не хочет это читать. Вместо этого SqlClient является ведущим, и то, что падает с повозки, добавляется в ADO.NET, и все.

В ADO.NET они поступили именно так: методы Async по умолчанию возвращаются к вариантам синхронизации.

Нет, это не так. API предоставляет асинхронные методы, которые по умолчанию возвращаются к методам синхронизации, но поставщики заменяют их реальными асинхронными операциями. @Mythz заявляет, что он использует IDbCommand и IDbConnection и делает это.

Это невозможно, и точка. Если вы это делаете, значит, вы либо делаете это неправильно, либо не пользуетесь интерфейсом. Вы не можете изобрести асинхронность, если базовый API не является асинхронным.

Нет, это не так. API предоставляет асинхронные методы, которые по умолчанию возвращаются к методам синхронизации, но поставщики заменяют их реальными асинхронными операциями. @Mythz заявляет, что он использует IDbCommand и IDbConnection и делает это.

Ни один официальный провайдер не делает этого, кроме SqlClient, все остальные, например ODP.NET, не реализуют какую-либо форму асинхронного кода и, таким образом, вызывающий код возвращается к вариантам синхронизации (асинхронные методы в DbDataReader / DbCommand и т. Д., Которые фактически выполняют код синхронизации ). поэтому пользовательский код вызывает асинхронный вариант, который выполняет операции синхронизации. Это приводит к тому, что на практике асинхронность не выполняется (поскольку на практике весь код просто синхронизируется). Возможно, поставщики devart реализуют async api в своей собственной реализации, не уверен.

В любом случае, дело не в том, чтобы делать все правильно, а в управлении версиями API.

@nvivo

Я открыл эту проблему, потому что считаю, что интерфейсы лучше описывают api и помогают при тестировании. Если это будет сделано, я не думаю, что они должны быть совместимы с API 15-летней давности, у которого были свои проблемы. Обратная совместимость никогда не была предметом обсуждения, пока вы, ребята, не перешли к этому вопросу.

Итак, вы знали, что основные интерфейсы ADO.NET устарели 10 лет назад, все было перемещено в базовые классы, но вы думали, что им следует просто отказаться от этого сейчас и вернуться к интерфейсам, по совпадению используя те же имена, что и существующие интерфейсы, но существующие интерфейсы больше не должны существовать, потому что обратная совместимость не требуется, верно? конечно, звучит законно.

Если вы хотите продвигать платформу вперед, вы со временем развиваете API и поддерживаете их параллельно, давая каждому возможность также поддерживать параллельные API и позволяя им планировать свой путь и их клиентов за их пределами. Их извлечение без предупреждения без надобности разрушает полагающуюся на них экосистему и понижает сложность всех последующих зависимостей.

Вы не можете добавить async api поверх sync api. Если вы сделали это с помощью IDbConnection или IDbCommand, вы сделали это неправильно. Если вы не используете эти интерфейсы, вам действительно нет смысла защищать с ними обратную совместимость.

Я бы хотел, чтобы вы перестали засорять эту ветку комментариями о вещах, о которых вы явно не знаете. Прочтите исходный код, если вы хотите узнать, как реализованы Async API, и прекратите слепо распространять ложь. Сторонняя библиотека не может расширить интерфейсы System.Data. Мы предоставляем независимый от реализации API, который для поддержки всех основных СУБД предоставляет минимальную зависимость, которую каждый поставщик ADO.NET реализует в своем внешнем API, а именно основные интерфейсы System.Data. Async API - это методы расширения от IDbConnection, которые негласно используют асинхронные API для конкретных поставщиков ADO.NET, которые их поддерживают. Внутри уже существуют конкретные зависимости от каждого поддерживаемого поставщика ADO.NET, независимо от поддержки асинхронности. Ваше предположение о том, что нам «на самом деле нет никакого смысла отстаивать какую-либо обратную совместимость с ними», неопытно и совершенно безосновательно.

Позвольте мне спросить об этом Microsoft со стороны забора (cc @davkean @YoungGah): допустим, это идеальный мир, и ничего никогда не возникало. Когда _до_ вы хотите что-то сломать? Основные версии вроде 6.0? Как-нибудь в другой раз? Аргумент против интерфейсов заключается в том, что они не имеют версии. Ну да, это действительно так, но _ если мы не меняем и абстрактные классы_, это тоже спорный вопрос. Итак ... можем ли мы внести здесь ясность?

Последующие действия:
Если ответ положительный (в какой-то момент после RTM будут изменения), то какие перерывы мы увидим? Дополнения, новые методы? Если я унаследую базовый класс своего провайдера, что произойдет, если вы добавите конфликтующий метод, который используют люди, и т. Д.?

Если ответ отрицательный (никогда): почему бы просто не добавить интерфейсы обратно?

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

Какие планы на будущее?

В этом случае мы не должны форсировать реализацию через абстрактные классы. ИМО

Microsoft не будет вносить изменения, нарушающие .NET 4.5. Это часть Windows. Совместимость - это король.

Microsoft может внести изменения в .NET Core, которые не повлияют на 4.5. Я сомневаюсь, что они опубликуют 1.0 RTM на чем-то низком уровне вроде ADO.NET, но планка ниже. Это не часть Windows, и версии .NET Core могут быть развернуты одновременно.

Абстрактные классы можно изменять - это не ломается. Просто добавьте виртуальный метод с реализацией по умолчанию. Это уже было сделано с помощью асинхронных методов ADO.NET. Я считаю, что с появлением .NET Core изменения в общих классах необходимо будет вносить совместно с выпусками .NET 4.5 для обеспечения совместимости. Кто-нибудь поправит меня, если это не так и относится только к интерфейсам: grin:

@FransBouma

Ни один официальный провайдер не делает этого, кроме SqlClient, все остальные, например ODP.NET, не реализуют какую-либо форму асинхронного кода, и поэтому вызывающий код возвращается к вариантам синхронизации.

Вы правы, но проблема не в API, а в большей лени или непонимании со стороны разработчиков. Коннектор MySql, например, повторно реализовал все свои асинхронные методы, создав TaskCompletionSource и дополнив их методами синхронизации, что нелепо. Они могли просто удалить половину своей кодовой базы и сохранить то же поведение.

Я не говорю, что интерфейсы решат эту проблему, но отсутствие поведения по умолчанию для async, по крайней мере, заставило бы некоторых из них задуматься над этим. Тот факт, что 90% технических специалистов не разбираются в асинхронных операциях, тоже не помогает.

Абстрактные классы можно изменять - это не ломается. Просто добавьте виртуальный метод с реализацией по умолчанию. Это уже было сделано с помощью асинхронных методов ADO.NET.

Это нарушение. Это ломается для всех библиотек, которые подклассифицировали эту реализацию, не зная, что она была добавлена, и люди затем принимают это мышление. О, эта реализация теперь поддерживается с помощью postgresql BAM ERROR, что произошло ...

Принудительная реализация абстракции БД неверна.

Неважно, это интерфейсы или базовый класс. Будут критические изменения. Но принудительная предопределенная реализация неверна.

Полиморфизм так не работает. Вы не можете переопределить метод, не зная об этом. Если ваша ссылка представляет собой DbConnection и вы вызываете QueryAsync, он вызовет только этот метод или то, как он был переопределен. Метод QueryAsync, который уже существует в подклассе, не будет вызываться.

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

@JamesNK

Если методы определены как абстрактные, в базовом классе не существует реализации. Это разрывает контракт для третьих сторон, поскольку требует от них добавления реализации в подкласс.

Если вы сделаете метод виртуальным, чтобы его можно было переопределить, тогда в базовом классе будет существовать реализация, которая не будет иметь смысла для подкласса. Это все еще не работает, потому что существует реализация, которая не была реализована автором библиотеки. Конечно, ваше приложение может компилироваться, и все в порядке, но кто-то вызывает этот метод, и он недействителен для подкласса. Это неверно. Это принудительная реализация, не принадлежащая к подклассу.

Итак, абстрактный класс, в котором может существовать реализация, не принадлежит подклассу. Или интерфейсы, в которых не существует реализации по умолчанию для третьих сторон.

@ phillip-haydon, поэтому он реализован как виртуальный метод, а не как абстрактный.

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

Это принудительная реализация, не принадлежащая к подклассу.

Тогда не кладите это туда.

@jamesnk

Не кладите это туда. Вот почему мы выступаем за удаление интерфейсов.

Сделать его виртуальным не решает проблемы. Не должно быть заранее определенной реализации. Конец истории

@JamesNK В данном случае мы не поместили его туда, _Microsoft_ поместила его туда, включив в аннотацию. Добавление методов, которые, как предполагается, работают для _все_ провайдеров, когда-либо наследовавших, я действительно не вижу, чтобы все прошло гладко или эффективно, даже если это не технически нарушено (я признаю, что предупреждения компиляции "следует использовать новые" _технически_ не нарушают). В _ большинстве_ случаев просто не будет общей или немедленной реализации. Так какая альтернатива? throw new NotImplementedException() внутри этого виртуального? Вряд ли это аргумент в пользу того, что он вообще существует, он изобилует большим количеством проблем (во время выполнения).

Давайте посмотрим на сегодняшний день: я бы предпочел, чтобы IDbAsyncConnection добавлялся, когда провайдер поддерживает его, а не кучу методов, которые синхронны под покровом, приводя к путанице и неэффективности, что у нас есть сегодня на этих рефераты.

Я бы предпочел, чтобы IDbAsyncConnection добавлялся, когда провайдер его поддерживает, а не кучу методов, которые синхронны под покровом, что приводит к путанице и неэффективности.

@NickCraver +1000 к этому. Как эта ошибка здесь, когда команда оракула просто не понимает, что означает асинхронность.

Вы можете сделать это с помощью интерфейсов. Проблема с ними в том, что вы не можете принимать аргументы, требующие нескольких интерфейсов, например, мне нужен тип, который является одновременно IDbAsyncConnection и IDbConnection. Вы теряете строгую типизацию, и вам нужно начинать запрашивать интерфейсы в стиле COM, который, на мой взгляд, не очень удобен для пользователя. Это инструмент в дизайне API, у которого есть свое место, но я не знаю, буду ли я использовать его по умолчанию.

Если реализация по умолчанию выбрасывала NotImplementedException, то прикрепление его к базовому классу было бы неправильным. Как я уже сказал, тогда не кладите это туда. Если вы видите, что кто-то это делает, поднимите вопрос.

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

@JamesNK предположительно IDbAsyncConnection унаследует здесь IDbConnection , но это не обязательно так - они могут иметь общие члены или наследовать от общей базы. Например, в Dapper мы, вероятно, реализовали бы следующее:

`` С #
IEnumerableЗапрос(это IDbConnection cnn, CommandDefinition cmd)

``` C#
Task<IEnumerable<T>> QueryAsync<T>(this IDbAsyncConnection cnn, CommandDefinition cmd)

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

_Edit: _ набрав это, я понимаю, насколько лучше Async в конце имени для всех этих ...

За прошедшие годы ADO.NET претерпела следующие важные изменения:

  1. В 2003 году (1.1) они внесли критическое изменение по сравнению с 1.0 и переработали его.
  2. В 2005 году (2.0) они перешли на модель поставщика с базовыми классами, которые существуют сегодня.
  3. В 2012 году (4.5) они добавили поддержку асинхронности, которая фактически ничего не изменила, кроме добавления новых методов, которые выполняли те же действия асинхронно.

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

Этот API уже долгое время стабилен. Если бы люди захотели, его можно было бы переделать в интерфейсы. Как обычно, технических проблем здесь нет, все сводится к шрамам, предпочтениям и эго.

Почему бы не вернуть интерфейсы и не пометить их как устаревшие?

Хотя эта идея была отброшена, мне интересно, могли ли нейтральные интерфейсы сборки помочь в такой ситуации, см. Этот http://davidfowl.com/assembly-neutral-interfaces/, а затем их реализацию
http://davidfowl.com/assembly-neutral-interfaces-implementation/

Я думаю, что интерфейсы, нейтральные к сборке, здесь отвлекают; если что-нибудь
чтобы случиться, это совершенно «обычное» дело, поскольку «общее» существует. Плюс это
спорный, так как функция испарилась.
28 ноября 2015 года в 17:38 «Шахид Хан» [email protected] написал:

Хотя эта идея была отброшена, мне интересно, нейтральна ли сборка
интерфейсы могли бы помочь в такой ситуации увидеть это
http://davidfowl.com/assembly-neutral-interfaces/, а затем их
реализация
http://davidfowl.com/assembly-neutral-interfaces-implementation/

-
Ответьте на это письмо напрямую или просмотрите его на GitHub
https://github.com/dotnet/corefx/issues/3480#issuecomment -160323344.

Что я наблюдаю:

  • Люди, стоящие за идеей CoreClr (новый блестящий фреймворк), имеют совершенно иное мышление, чем люди, стоящие за его реализацией (обратная совместимость с 15-летней кодовой базой является королем).

Что я думаю:

  • Удаляя интерфейсы, вы ухудшаете ситуацию .
  • Ничего не устареет, пока не будет отмечено [Устаревшее]. И неважно, кто что думает в любой момент. Это контракт, и если вы его просто не удовлетворяете, значит, это не так.

Что я хочу:

  • Используйте интерфейс (ы) в качестве базовой поверхности API, а не базовый класс (ы).

Что я чувствую:

  • Мы находимся в конце 2015 года, и очень грустно видеть, как люди спорят по этому поводу.

Версии интерфейсов не поддерживаются.

Разве интерфейсы можно легко версировать с помощью наследования интерфейсов? И если он делает что-то совершенно другое; ну это другой интерфейс.

interface IOldInterface {}
interface INewInterface : IOldInterface {}
interface IDifferentInterface {}

class SomeClass : IOldInterface, INewInterface, IDifferentInterface
{
}

Только не называйте это IInterfaceV2 , IInterfaceV3 он должен объяснять, что он добавляет.

Чтобы поместить в контекст [Obsolete] старый интерфейс и использовать некоторые новые интерфейсы и называть их тем, чем они являются на самом деле; а не неасинхронные методы, которые кажутся нормальными в наши дни.

public interface IDbUtilityProviderFactory 
{
    IDbConnectionStringBuilder CreateConnectionStringBuilder();
    IDbParameter CreateParameter();
}

public interface IDbBlockingProviderFactory : IDbUtilityProviderFactory 
{
    IDbBlockingCommand CreateBlockingCommand();
    IDbBlockingConnection CreateBlockingConnection();
}

public interface IDbAyncProviderFactory : IDbUtilityProviderFactory 
{
    IDbCommandAsync CreateAsyncCommand();
    IDbConnectionAsync CreateAsyncConnection();
}

@abatishchev

Люди, стоящие за идеей CoreClr (новый блестящий фреймворк), имеют совершенно иное мышление, чем люди, стоящие за его реализацией (обратная совместимость с 15-летней кодовой базой является королем).

Спасибо, что прояснили это, похоже, на это нужно указать. В целом я считаю, что команды MS глубоко заботятся об обратной совместимости, которая жизненно важна для развития обоих языков и их платформ. Просто решения вокруг System.Data не принимаются с учетом более широкой экосистемы, которую эти базовые абстракции должны обслуживать в равной степени.

  • Удаляя интерфейсы, вы ухудшаете ситуацию.
  • Ничего не устареет, пока не будет отмечено [Устаревшее]. И неважно, кто что думает в любой момент. Это контракт, и если вы его просто не удовлетворяете, значит, это не так.

Точно.

По поводу версионирования интерфейсов. Поправьте меня, если я ошибаюсь, но я думал, что суть CoreClr в более мелкомасштабном независимом управлении версиями? Критическое изменение? Бум! Выпущена новая мажорная версия.
Похоже, что после 15 лет опыта в дизайне вы собираетесь повторить те же ошибки, но теперь, имея независимые версии и выпущенные пакеты nuget. Приведенные выше аргументы идентичны старому доброму монолитному фреймворку, хотя его больше нет.
Если обратная совместимость необходима, вы просто не можете удалить эти интерфейсы. Если это не так, давайте прекратим говорить об этом и спроектируем API с нуля, на этот раз прислушиваясь к основным авторам ORM и другим опытным разработчикам ADO.NET.
Спасибо.

@abatishchev очень хорошие моменты. Я тоже задавался вопросом: в чем на самом деле смысл аргумента об обратной совместимости? Если в CoreClr добавлена ​​новая функция, все, что ее использует, не будет работать в .net full, поэтому для безопасности можно использовать только обычное поведение. (это никогда не помогало).

Прошу прощения за долгое молчание с моей стороны.

Перенос на .NET Core

Во-первых, давайте поговорим о слоне в комнате, а именно о том, что .NET Core не имеет такого количества доступных API, на которое многие, в том числе и мы, надеялись.

Я работаю со своей командой над составлением набора документов о том, как мы собираемся подойти к области переноса существующих ресурсов на .NET Core.

Мы планируем перенести больше функций, которые в настоящее время существуют только в .NET Framework / Mono, на .NET Core. В этом документе будет рассказано, как мы собираемся это сделать, как мы расставляем приоритеты и каковы будут механизмы. Я не только хотел бы, чтобы эта работа шла открыто, я также хотел бы, чтобы сообщество помогло нам в переносе большей функциональности.

Критические изменения

Есть одна область, которая вызывает большую путаницу, когда люди говорят о .NET Core. Позвольте мне прояснить одну вещь:

Это не критическое изменение, если в .NET Core меньше API, чем в .NET Framework.

Причина в том, что .NET Core является новой платформой и технически может иметь произвольный набор API. Однако, конечно, нам не нужен произвольный набор - это то, что мы делали в прошлом. Цель .NET Core - создать историю, в которой люди могут создавать библиотеки (а с консольными приложениями в определенной степени даже приложения), которые будут работать в .NET Framework и .NET Core. Для этого требуется подмножество обеих платформ, которое на 100% совместимо. В этом контексте вы услышите, как мы говорим о критических изменениях.

Вдобавок к этому мы стремимся иметь высокую планку совместимости с .NET Core. Другими словами, мы не планируем вносить критические изменения API между одной версией .NET Core API и другой.

Интерфейсы

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

WinRT, основанный на COM и, следовательно, сильно зависящий от интерфейсов, решает эту проблему путем создания дополнительных интерфейсов, таких как IFoo , IFoo2 , IFoo3 . Это выполнимо, но это определенно беспорядочно без среды выполнения или языковой функции, которая сделала бы это терпимым. Пока такой возможности нет. Однако, как член команды языковых дизайнеров, мне очень интересно услышать предложения. Другие языки и платформы имеют похожие идеи в этой области, и я также активно изучаю варианты (такие как mix-ins / traits, Swift extension-everything или элементы по умолчанию для интерфейсов).

Поскольку мы по-прежнему заботимся об обратной совместимости, мы обычно предпочитаем абстрактные базовые типы интерфейсам.

Интерфейсы ADO.NET

С учетом всего сказанного, давайте поговорим об исходном вопросе в этом потоке: раскрытии интерфейсов провайдера ADO.NET.

Как объяснил Дэвид: мы считали их устаревшими, когда были введены абстрактные базовые типы, что было в .NET 2 / Visual Studio 2005. Похоже, есть твердое убеждение, что наличие этих интерфейсов имеет решающее значение для переноса фреймворков ORM на .NET Core. На мой взгляд, это является достаточным доказательством того, что мы должны переносить интерфейсы на .NET Core.

Однако, как и в случае со всеми новыми API-интерфейсами, мы должны помнить об одной из основных целей .NET Core, которая заключается в создании компонентного стека. Интерфейс IDataReader зависит от DataTable , который зависит от DataSet . Как указано в dotnet / runtime # 14302, мы не против добавления поддержки для DataTable но мы считаем DataSet устаревшим. Тем не менее, мы все равно можем добавить его как отдельный пакет, но в любом случае это потребует разрыва цепочки зависимостей от интерфейсов -> DataTable -> DataSet . Я буду работать с @YoungGah, чтобы посмотреть, что мы можем там сделать.

Сможет ли этот подход решить проблемы?

Если я не ошибаюсь, единственная зависимость DataTable в IDataReader - это
GetSchemaTable (), уже подробно обсужденный в DataTable
цепь. Однако я с готовностью признаю, что тот факт, что существует
надеюсь добавить _ некоторые_ аналогичные функции в более позднее время (будь то
через DataTable или нет), очень неудобно раскрывать это на
интерфейс, так как расширение интерфейса в дальнейшем проблематично. Не было бы
так же просто, как «удалить метод сейчас, добавить что-то еще позже»
5 декабря 2015 года, 12:17, "Immo Landwerth" [email protected] написал:

Прошу прощения за долгое молчание с моей стороны.
Перенос на .NET Core

Во-первых, давайте поговорим о слоне в комнате, то есть о том .NET.
Core не имеет столько API, сколько доступно многим, включая
нам - хотелось бы.

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

Мы планируем перенести больше функций, которые в настоящее время
существует от .NET Framework / Mono до .NET Core. Этот документ вызовет
как мы собираемся это сделать, как расставляем приоритеты и какие механики будут
быть. Я не только хотел бы, чтобы эта работа шла под открытым небом, я также хотел бы
Включите сообщество, помогите нам портировать больше функций.
Критические изменения

Есть одна область, которая вызывает большую путаницу, когда люди говорят о
.NET Core. Позвольте мне прояснить одну вещь:

Это не критическое изменение, если в .NET Core меньше API, чем в .NET.
Фреймворк.

Причина в том, что .NET Core - это новая платформа, и технически она может
иметь произвольный набор API. Однако, конечно, мы не хотим
произвольный набор
http://blogs.msdn.com/b/dotnet/archive/2014/12/04/introduction-net-core.aspx
- это то, что мы делали в прошлом. Цель .NET Core - иметь
история, в которой люди могут создавать библиотеки (и с консольными приложениями для определенных
расширять даже приложения), которые будут работать в .NET Framework и .NET Core. Этот
требует наличия подмножества обеих платформ, что составляет 100%
совместимый. В этом контексте вы услышите, как мы говорим о критических изменениях.

Вдобавок к этому мы стремимся иметь высокую планку совместимости с .NET Core.
Другими словами, мы не планируем вносить критические изменения API между
одна версия .NET Core API и другая.
Интерфейсы

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

WinRT, основанный на COM и, следовательно, сильно зависящий от интерфейсов,
решает эту проблему, создавая больше интерфейсов, таких как IFoo, IFoo2,
IFoo3. Это выполнимо, но это определенно беспорядочно без среды выполнения или
языковая функция, чтобы сделать его терпимым. Пока такой возможности нет.
Однако, как член команды языковых дизайнеров, мне очень интересно
услышать предложения. У других языков и платформ есть похожие идеи в том, что
пространство, и я также активно изучаю варианты (например,
mix-ins / traits, расширение Swift-everything или элементы по умолчанию для
интерфейсы).

Поскольку мы по-прежнему заботимся об обратной совместимости, мы обычно отдаем предпочтение
абстрактные базовые типы поверх интерфейсов.
Интерфейсы ADO.NET

После всего сказанного давайте поговорим об исходном вопросе в этой теме:
предоставление интерфейсов провайдера ADO.NET.

Как объяснил Дэвид: мы считали их устаревшими, когда абстрактная база
были введены типы, которые были в .NET 2 / Visual Studio 2005. Кажется,
что есть твердое убеждение, что наличие этих интерфейсов имеет решающее значение для
портировать ORM-фреймворки на .NET Core. Для меня это достаточно доказательств
что мы должны перенести интерфейсы на .NET Core.

Однако, как и со всеми новыми API, мы должны помнить об одном из
Основные цели .NET Core - компонентный стек. В
интерфейс IDataReader зависит от DataTable, у которого есть
зависимость от DataSet. Как указано в dotnet / runtime # 14302
https://github.com/dotnet/corefx/issues/1039 , мы не против добавления
поддержка DataTable, но мы действительно не хотим переносить DataSet. Так
добавление интерфейсов потребует разрыва этой зависимости. Я буду работать с
с @YoungGah https://github.com/YoungGah, чтобы увидеть, что мы можем там сделать.

Сможет ли этот подход решить проблемы?

-
Ответьте на это письмо напрямую или просмотрите его на GitHub
https://github.com/dotnet/corefx/issues/3480#issuecomment -162115855.

Да, IDataReader зависит от DataTable, который зависит от DataSet.

Как упоминалось ранее, мы не можем удалять элементы из интерфейсов, поэтому нам нужно будет сломать эту зависимость другим способом; либо не портируя интерфейс, либо нарушив зависимость DataTable -> DataSet.

Сможет ли этот подход решить проблемы?

Да, восстановление интерфейсов ADO.NET даже без метода GetSchemaTable() решит тяжелые зависимости от проблем интерфейса ADO.NET, с которыми я сейчас сталкиваюсь.

Я предполагаю нарушение зависимости DataTable -> DataSet, если это означает, что GetSchemaTable() также будет включен, будет предпочтительным подходом для тех, кто полагается на GetSchemaTable() (так что это будет мой голос), но Я бы уделил больше внимания разработчикам, на которые это влияет.

@terrajobst благодарим вас за ваше резюме и за то, что вы поделились своими соображениями.

@terrajobst спасибо за резюме и пояснения. Я поддерживаю Npgsql, поэтому пишу с точки зрения поставщика ADO.NET, а не ORM.

В .NET Core Microsoft, похоже, хотела удалить некоторые давно унаследованные функции ADO.NET, а именно DataTable / DataSet и интерфейсы. Это создает более совершенный и чистый API, продвигающийся вперед, но создает значительную работу для пользователей, уже зависящих от интерфейсов и DataTable / DataSet API.

Я лично считаю, что уничтожение DataTable / DataSet - это хорошо, и что следует ввести новый и лучший API метаданных (я думаю, что это верно даже без уничтожения DataTable / DataSet). Я не преуменьшаю
боль, вызванная этой поломкой для потребителей ORM (и других), но нужно помнить одну вещь: если когда-нибудь появится возможность очистить и внедрить поломку, .NET Core - это такая возможность.

Дополнительным разочаровывающим фактором здесь является то, что сохранение интерфейсов ADO.NET также означает сохранение DataTable / DataSet. Другими словами, хотя я лично не очень сильно отношусь к проблеме интерфейсов, их сохранение означает сохранение DataTable / DataSet, и это кажется более проблематичным.

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

PS Что бы вы ни делали, не идите по пути взрыва интерфейса, то есть IFoo2, IFoo3. Это просто не решение.
PPS Если вы все же решите создать новый API метаданных, не относящийся к DataTable, в .NET Core и хотите, чтобы библиотеки .NET Core работали в .NET Framework, это означает, что вам придется выпустить новую .NET Framework с новым API вместе с .NET Core.

@terrajobst Спасибо, что @roji в этом: ядро ​​.NET - это

Тем не менее, если что-то не изменится к лучшему для ADO.NET (т.е. он получит реальный дизайн, в котором разработан общий API, который затем специализируется на SqlClient, а не наоборот! SQL Server, но в других базах данных, добавляются к общему API и не оставляются на усмотрение автора поставщика ADO.NET), тогда лучше всего переносить как можно больше, включая интерфейсы и сторонние разработчики #ifdef сами вокруг выбоин, которые останутся.

Однако зависимость DataTable может быть проблемой, поскольку интерфейс IDataReader затруднит сохранение обратной совместимости с .NET full _if_ datatable в любой форме, не портированной. Но в любом случае я думаю, что это безнадежное дело. MS несколько раз говорила, что .NET full не будет получать столько / так часто обновлений, как ядро ​​.NET, поэтому, если что-то _new_ добавлено в ядро ​​.NET, никто не сможет его использовать, поскольку его использование делает библиотеку сразу несовместим с .NET полной. Скорее всего, я что-то здесь пропущу, так что если это так, поправьте меня, пожалуйста :)

Уже одно это делает ситуацию странной: должна быть обратная совместимость, но на практике это кажется труднодостижимым и в любом случае отвлекающим маневром. IMHO, если это решено в первую очередь, результат этого можно использовать для принятия правильных решений о том, что делать с API-интерфейсами .NET core, т.е. улучшать их вместо того, чтобы перетаскивать старый плохо спроектированный мусор из .NET полностью. Это не значит, что все API-интерфейсы плохо спроектированы, однако с ADO.NET (как я описал в предыдущем посте) все не делалось должным образом в течение многих лет. Сделать полный перерыв и вместо этого внедрить систему, которая может быть более надежной (JDBC все еще сильна, ODBC все еще работает, как 25 лет назад) и адаптивная к изменениям предпочтительнее.

Если подумать об этом немного подробнее, комментарий

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

С @roji все наоборот : короткие итерации включаются без нарушения работы API.

Если вы разработчик .Net и ваша сборка ломается каждую неделю из-за того, что API базового фреймворка постоянно меняется, то вскоре вы начнете рассматривать другую платформу.

Так что это быстрая итерация, основанная на неразрывных изменениях.

(отредактировано)
Вы можете выполнять итерацию, не нарушая изменений, пока вам не нужно будет, например, добавить что-то в интерфейс класса, изменить поведение (!) Или добавить поведение, что не является критическим изменением в буквальном смысле (изменение поведения - это), но использовать его на Ядро .net сделает ваш код несовместимым с .net full, поэтому в этом смысле ядро ​​.net больше не будет обратно совместимым с .net full _ для этого фрагмента кода_. Какое ИМХО сводится к любому ядру .NET, всегда будет иметь те же (классовые) интерфейсы и поведение, что и в .NET full, до последнего байта (что IMHO неустойчиво) или получит новые функции, которые будут перенесены позже (что буквально то, что MS сказал, кстати,) до .NET full, что фактически делает его несовместимым с предыдущими версиями. Это, конечно, зависит от того, на какой стороне забора вы находитесь: если вы скажете: «существует общий набор (классовых) интерфейсов X с определенным поведением B, и оба ядра .NET и .NET полностью реализуют их, и X и B победили» «Изменения в будущем», это по-прежнему будет означать, что есть новая структура за пределами X и B, которая получит новые вещи, и именно там вещи могут измениться, а также то, где лежит будущее.

С этим можно пойти очень далеко, например, что интерфейсы / классы, используемые в X и B в ядре .NET, на самом деле являются оболочками вокруг новых классов / интерфейсов в ядре .NET. Затем разработчик, использующий их, может использовать либо X & B, либо новые с улучшенным дизайном и без API, общего с .NET full.

Поскольку мы уже должны #ifdef обходить недостающие вещи в X и B, при поддержке обеих структур, IMHO предпочтительнее просто иметь возможность настраивать таргетинг на новые интерфейсы / классы в ядре .NET, как только поведение рано или поздно изменится (может быть, даже очень незаметно) (например, другое исключение в данной ситуации) в любом случае возникнет там, поэтому «перенос» кода на ядро ​​.NET с его _new_ API (не X&B) будет лучше. Мы все равно должны портировать, по крайней мере, я так вижу.

@ryanbnl , я согласен с @FransBouma. Дело не в том, что мы хотим ломать API. Дело в том, что ограничение .NET Core для запуска в .NET Framework означает, что вы никогда не сможете добавить что-либо к любому интерфейсу .NET Core или добавить абстрактный член к любому абстрактному базовому классу. Эти два изменения на самом деле не нарушают обратную совместимость в реальном смысле для тех, кто использует .NET Core, они нарушают совместимость с .NET Framework.

@roji, если это не новый внешний пакет из фреймворка (например, не GAC), когда он может быть совместим как с фреймворком, так и с ядром и работать в собственном ритме; но тогда это может быть еще больше изменений для поставщиков ORM, и имя System.Data.IDbConnection уже занято ...

@benaadams , это отличные от Nuget , такие как ADO.NET. Однако они, похоже, покрывают достаточно места API, чтобы вызывать беспокойство - .NET Core не сможет развить ни один из них (читайте: добавление методов интерфейса или абстрактных методов), не становясь неработоспособным.

Я не уверен, что вы имеете в виду, говоря об IDbConnection ...

@roji просто означал новый пакет, который предоставляет эти типы, например System.Data.Database ; чтобы оставаться совместимым как с ядром, так и с полной, нельзя было переопределить какие-либо типы, которые были бы GAC в полной структуре, иначе это могло бы конфликтовать.

На точке nuget; если по какой-либо причине это не могло существовать в nuget как для полной, так и для основной версии; и исключить текущую публикацию System.Data api 4.6.1+?

Сейчас это вызовет еще большую боль; но некоторая совместимость уже нарушена, при этом отбрасываются интерфейсы или отбрасывается только DataSet поэтому поставщикам ORM уже необходимо выполнить некоторую переделку для coreclr.

Совершенно новый api, который жил в nuget и вне инфраструктуры GAC'd, мог быть обратно совместим для использования с netstandard1.2, например 4.5.2+, coreclr, UWP, mono / Xamarin и т. Д. Хотя сейчас это было бы немного больнее - но это, наверное, лучшее время, чем позже.

Учитывая, что новые API-интерфейсы используются для устранения ахемы и тому подобного, обозначение DataSet не появится (или DataTable ), следует ли это закрыть? Похоже, что базовые классы - это путь вперед, основанный на комментариях в dotnet / corefx # 5609 и пересылке типов, что означает, что интерфейсы бесполезны с учетом GetSchemaTable() а некоторых других нет, чтобы передать их для совместимости ... это справедливо?

Что нужно закрыть? Если у нас не может быть GetSchemaTable() из-за зависимости DataTable / DataSet, это одно, но интерфейсы все равно следует восстановить (без GetSchema, если необходимо) и упростить перенос существующих баз кода с глубокими зависимостями от них. Отсутствующие интерфейсы являются блокировщиком, я все еще жду релиза с ними, прежде чем мы сможем начать работу по поддержке dnx / core.

Я согласен с @mythz , интерфейсы - это еще одна тема, очень важная. Возможно, не для большинства пользователей, но те же самые пользователи используют код, который написан небольшой группой, и этот код _is_ полагается на эти интерфейсы (а также другие важные отсутствующие функции ADO.NET, такие как DbProviderFactory).

Честно говоря, я не очень надеюсь, что благодаря сильному стремлению к ярлыку «RTM» мы получим надежный API с 1.0. Это будет снова как .NET 2.0: все ошибки, допущенные в первой версии, будут исправлены.

@FransBouma

Добавление интерфейсов в .NET Core было бы дополнительным изменением. Так что, даже если он не подходит для V1, его можно добавить в любую следующую версию, даже в 1.1.

все ошибки, допущенные в первой версии, будут исправлены.

Без обид, но так работает софт.

@terrajobst

Так что, даже если он не подходит для V1, его можно добавить в любую следующую версию, даже в 1.1.

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

Без обид, но так работает софт.

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

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

Даже ошибку можно исправить позже, но она еще не сделана, это хороший повод не делать в первую очередь, не так ли?

Вы, ребята, слишком остро реагируете. Я сомневаюсь, что последствия этого будут такими же, как и у старого .NET.

Поскольку coreclr входит в состав каждого приложения, унаследованное значение имеет совсем другое значение. Как и почти никого не волнует, не перенесены ли функции из asp.net mvc 5 в mvc 4 или 3. Унаследованное здесь будет иметь другое значение, и история других проектов показывает это.

Хорошо, что @terrajobst открыт для рассмотрения в следующих версиях.

@nvivo, пожалуйста, не пытайтесь заговорить о последствиях, с которыми _I_ должен иметь дело, потому что вам не нужно иметь с ними дело, а мне это нужно.

Спасибо @FransBouma за то, что поставили меня на место. Было моей ошибкой думать, что я могу прокомментировать проблему. Вы определенно более квалифицированы, чем я, чтобы знать, какие вещи влияют на мою работу.

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

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

Спасибо @FransBouma.

_sigh_ Где мне все это сказать? Все, что я говорю, это, пожалуйста, не преуменьшайте значение, поскольку вы делаете это со словами «вы слишком остро реагируете», я не думаю, что я слишком остро реагирую. Под «вам не нужно иметь с ними дело» я имею в виду последствия для _me_. Поскольку я знаю, что это такое, я так же реагирую. По-видимому, это «чрезмерная реакция».

Но как бы там ни было.

У нас есть ответы на этот вопрос здесь и здесь .

Официальный ответ: интерфейсов не будет в .NET Core 1.0, и, хотя маловероятно, они могут быть рассмотрены для будущих выпусков в какой-то иной форме, чем в .NET.

Я закрываю этот вопрос, так как исходный вопрос был решен.

@nvivo Спасибо, но лучше всего оставлять любые официальные ответы людям, фактически ответственным за проект, которые также могут самостоятельно закрывать проблемы, как только они решат, что они решены.

@terrajobst Есть ли обновленный официальный ответ / график для интерфейсов? и как лучше всего отслеживать этот рабочий элемент в будущем? следует ли нам открыть новый выпуск или вы продолжите присылать здесь какие-либо обновления?

Оставим это пока открытым. На мой взгляд, ответ был не «давайте не будем раскрывать интерфейсы». Ответ был: «давайте найдем способ раскрыть их, но давайте подумаем, что это значит для зависимости DataTable».

Извините, что вернулся к вам так поздно. Обсудив различные варианты в нашей команде, мы решили вернуть интерфейсы с пустым классом DataTable. Это не идеальное решение, но, учитывая временные рамки RTM, этот подход гарантирует, что мы сможем реализовать жизнеспособные варианты использования DataTable / DataSet в будущем. Мы постараемся ввести интерфейсы для System.Data.Common от v1 RTM; SqlClient не будет реализовывать интерфейсы v1. Благодарим за отзыв и терпение. Ваша обратная связь - ключевая часть превращения стека данных в жизнеспособный продукт.

@YoungGah спасибо за обновление, если классы DataTable будут просто пустыми заполнителями, что требует так много времени / усилий (т.е. удерживает их) от реализации SqlClient v1?

@mythz Стоимость заключается в реализации интерфейсов в базовом типе / перенаправлении их существующим методам. Стоимость должна быть минимальной, но обычно все проявляется: smile:

Мы добавили следующие интерфейсы в .Net CoreFX в System.Data.Common

IDataParameter
IDataParameterCollection
IDataReader
IDataRecord
IDbCommand
IDbConnection
IDbDataParameter
IDbTransaction

Это было сделано в ПР https://github.com/dotnet/corefx/pull/6359

@ saurabh500 Отличный материал, спасибо!

: +1:

: +1:

Потрясающие; есть ли веха для этого, чтобы поразить nuget? rc3?

25 февраля 2016 г., в 02:54, Саураб Сингх [email protected]
написал:

Мы добавили следующие интерфейсы в .Net CoreFX в System.Data.Common

IDataParameter
IDataParameterCollection
IDataReader
IDataRecord
IDbCommand
IDbConnection
IDbDataParameter
IDbTransaction

Это было сделано в PR dotnet / corefx # 6359 https://github.com/dotnet/corefx/pull/6359

-
Ответьте на это письмо напрямую или просмотрите его на GitHub
https://github.com/dotnet/corefx/issues/3480#issuecomment -188577701.

С уважением,

Марк

Как прокомментировали PR, нам нужно понять, почему на этих интерфейсах нет асинхронных методов. Как было предложено, это в основном урезанная версия интерфейсов ADO.NET 1.1, и я не думаю, что идея должна заключаться только в совместимости со старым кодом.

Интерфейсы должны быть ориентированы на текущее состояние ado.net, поскольку асинхронные методы должны быть способом по умолчанию для доступа к любой базе данных сегодня. Без реальной поддержки асинхронных методов эти интерфейсы бесполезны для современной разработки.
разработка.

И даже включая асинхронные методы из .NET 4.5, следует также добавить некоторые дополнительные методы, такие как DbTrabsaction.CommitAsync.

Провайдер postgres добавил в свой API несколько дополнительных методов, таких как CommitAsync, которые весьма полезны и необходимы.

Текущие интерфейсы и так хороши. Последствия их изменения слишком велики.

Асинхронная модель сильно отличается от синхронной, и, как вы, возможно, знаете, если вы выберете асинхронную модель, вы должны сделать это полностью. Следовательно, действительно нет причин иметь одинаковые интерфейсы для обоих API. Создайте новые для асинхронного API.

Если команда .NET хотела предоставить более современный API, почему бы просто не создать новый API, который не называется ADO.NET? Никакого наследия, которому можно было бы препятствовать, и никаких жалоб от сообщества. Это также хорошо сочетается с тем, как будет распространяться dnx? т.е. независимые пакеты.

: +1: по интерфейсам хороший компромисс.

Я не думаю, что идея должна заключаться только в совместимости со старым кодом.

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

Без реальной поддержки асинхронных методов эти интерфейсы бесполезны для современной разработки.

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

Я твердо верю, что async методы не должны _не_ быть в базовых классах, если реализация по умолчанию является оболочкой синхронизации - это плохо и расточительно. Если есть другое предложение, пусть будет так, но опять же: это должен быть другой вопрос.

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

Я выступаю за дополнительный интерфейс для async, если это необходимо. Что меня не устраивает, так это то, что у меня есть что-то, что определяет официальный контракт для ADO.NET (что такое интерфейсы), но нигде в нем нет асинхронных методов.

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

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

Я согласен, это основная причина, по которой большинство провайдеров не утруждают себя реализацией настоящего async api. Но изменение этого приведет к поломке гораздо большего количества кода и, вероятно, вызовет гораздо больше шума, чем удаление интерфейсов, поскольку базовые классы были фактическим API для поставщиков с 2.0.

Обновление библиотеки, чтобы не использовать какой-либо из интерфейсов 1.1, почти не повлияет на работу по сравнению с удалением всего асинхронного кода, написанного в последние годы, что было бы катастрофой. Компромисс заключается в обоих. Любой код, написанный сегодня, должен использовать async apis, поэтому исключать это не имеет никакого смысла.

Любой код, написанный сегодня, должен использовать асинхронные API.

Я не хочу ранить слишком сильно, но этот идеальный мир очень далек от реальности. Асинхронный режим очень распространен и заразителен. Вы просто не можете полагаться только на асинхронные API в библиотеках и ожидать, что целые приложения будут асинхронными потребителями (изменяя _тон_ их кода также на асинхронный) по прихоти. Sync -> Async везде также очень плохо из-за множества тупиковых ситуаций и соображений эффективности. Синхронный код будет писать еще много лет.

Оба API крайне необходимы. Дело в том, что давайте не будем удалять текущие или откладывать их появление для гипотетического и еще не разработанного нового набора. О втором / новом комплекте мы можем позаботиться самостоятельно.

Обновление библиотеки, чтобы не использовать какой-либо из интерфейсов 1.1, практически не повлияет на результат по сравнению с удалением всего асинхронного кода, написанного в последние годы.

Что вы имеете в виду? Для такого кода не существовало асинхронных API. Если вы полагаетесь на такие API, они не зависят от базового класса или интерфейса, а напрямую от поставщика. Это не повлияет на это.

Любой код, написанный сегодня, должен использовать async apis, поэтому исключать это не имеет никакого смысла.

Упускать много вещей бессмысленно ... за исключением того факта, что все мы ограничены ресурсами (особенно временем). Я не верю, что кто-то что-то упустил _ навсегда_. Ничего особенного. Это просто еще не сделано. Я бы открыл еще одну проблему специально для того, чтобы начать спецификацию асинхронных интерфейсов для будущего поколения.

Что вы имеете в виду? Для такого кода не существовало асинхронных API. Если вы полагаетесь на такие API, они не зависят от базового класса или интерфейса, а напрямую от поставщика. Это не повлияет на это.

.NET 4.5 представил асинхронные методы для базовых классов провайдера. Это было в 2012 году, почти 4 года назад, поэтому какое-то время он был частью API-интерфейса поставщика ADO.NET. Entity Framework 6 (выпущенный в 2013 году) зависит от этого асинхронного API для всех поставщиков.

Асинхронные методы уже достаточно долго являются частью ADO.NET, и многие люди закричали бы, если бы они не были включены в .NET Core. У меня есть _legacy code_, который использует асинхронные методы в ADO.NET.

Я выступаю за то, чтобы, поскольку они _ уже_ часть ADO.NET, это также должно присутствовать в новом интерфейсном API.

Если люди хотят (и должны) использовать асинхронные API, они уже могут
что _перед этим изменением_ с помощью базовых типов. В конечном итоге запрос
поддержка интерфейсов была сделана из соображений обратной совместимости;
добавление методов к интерфейсу полностью избавляет от этого вопроса.
Тем не менее, это практически возможно как _extension методы_ и
проверка типов на соответствие абстрактным базовым типам, но ... довольно уродливо и не
стоит боли ИМО.

Так; короткая версия: я лично не могу отказаться от добавления асинхронности в
интерфейсов, так как это разрушает то, для чего мы хотели их в первом
место. Если вам нужен асинхронный режим: вам нужно кодировать базовые классы или использовать
инструменты, которые скрывают эти детали для вас.

Я выступаю за то, чтобы, поскольку они уже являются частью ADO.NET, это также должно присутствовать в новом интерфейсном API.

Вы совершенно неправильно понимаете цель этих интерфейсов ADO.NET, которая заключается в поддержании совместимости с существующим кодом. Это не _ новые_ интерфейсы, это _ существующие_ интерфейсы. Если вы хотите получить доступ к более новым API, обратитесь к конкретным базовым типам.

@nvivo Извините, я просто не слежу за вами - я говорил об интерфейсных API - их никогда не существовало. В базовых типах уже есть все те же методы *Async - чего-то конкретного не хватает? Я думаю, вы утверждаете, что они должны быть объединены в интерфейсы ... да, конечно, но это еще одна проблема, которую я призываю вас открыть.

Я бы предпочел, чтобы они были интерфейсом с самого начала, поскольку базовые реализации, необходимые для работы текущего подхода (асинхронность поверх синхронизации), представляют собой ужасный компромисс, позволяющий заставить весь подход работать. Но у нас также не может быть обоих способов: либо они перемещаются к интерфейсам, либо присутствуют (как в текущем случае), чтобы минимизировать перерывы.

Да, я думаю, мы здесь ходим кругами. Я уже говорил об этом раньше, я не думаю, что интерфейсы нужно добавлять _ только_ для облегчения портирования кода. С точки зрения совместимости базовые классы были официальным API для ADO.NET с 2005 года, и это то, что реализуют поставщики. Все, что использует IDbCommand или IDbConnection, может быть легко портировано (и должно быть портировано) для использования базовых классов с поиском / заменой и не имеет недостатков.

Я знаю, что вы не являетесь поклонником ifdefs, но поддержка этого для новой платформы в любом случае будет только частью миграции.

Я согласен, что это должны были быть интерфейсы с самого начала, но поскольку их не было, я бы хотел, чтобы эта проблема не повторялась. Если интерфейсы добавляются, они должны, по крайней мере, представлять текущий API, а не то, что было десять лет назад. Асинхронные методы являются неотъемлемой частью текущего API, и Microsoft движется в этом направлении уже довольно давно. Он по-прежнему будет совместим с исходным кодом, только более полным.

@mgravell

Если люди хотят (и должны) использовать асинхронные API, они уже могут сделать это _ до этого изменения_, используя базовые типы.

Дело не в способности что-либо делать. Это об архитектуре. Интерфейсы - это контракты, .NET Core - это новый фреймворк, который добавляет этот контракт в обновленную версию API.

Ядро .NET не должно добавлять официальный контракт к новому API только для того, чтобы помочь перенести действительно старый код, в то время как большая часть других вещей все равно будет отсутствовать. Если это вызывает беспокойство, люди просто не ищут достаточно причин, по которым им все равно нужно будет изменить свой код.

Если это все, чем занимается команда, то ничего страшного ... ИМО, это просто плохой выбор.

Все, что использует IDbCommand или IDbConnection, может быть легко портировано (и должно быть портировано) для использования базовых классов с поиском / заменой и не имеет недостатков.

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

Я знаю, ты не фанат ifdefs

Любые решения, требующие от конечных клиентов использования ifdefs, являются неудовлетворительным опытом разработки и не запускаются, т. Е. Никогда не будет успешного продукта, требующего, чтобы клиенты засоряли свой код #defs, когда существуют альтернативы.

Если интерфейсы добавляются, они должны как минимум представлять текущий API.

Это не новые интерфейсы, это восстановленные интерфейсы. Текущие и будущие API являются базовыми классами, а не этими интерфейсами. Здесь не должно быть проблем, вы можете забыть, что эти интерфейсы существуют, и продолжать использовать базовые типы так же, как и до восстановления этих интерфейсов.

В эту ветку больше не добавляется никакой новой ценности. Существующие интерфейсы ADO.NET были восстановлены, поэтому этот поток можно остановить. Единственное, что требуется от этого потока, - это обновления DataTable и GetSchemaTable() поскольку они относятся к существующим интерфейсам. Если вы хотите предложить архитектурные изменения или отстаивать новые интерфейсы, откройте новую проблему, которая предотвратит спам всех в этом списке.

@mythz давай соглашаемся не соглашаться.

Просто добавив свои 2 цента в качестве другого разработчика ORM, абстрактные классы всегда являются запахом кода, когда они не поддерживаются интерфейсом. Хотелось бы, чтобы новые интерфейсы соответствовали абстрактным классам и сигнатурам методов, перегруженным интерфейсным API с минимальными требованиями.

Большое спасибо сообществу за высказывание.

абстрактные классы всегда являются запахом кода, когда они не поддерживаются интерфейсом

@psibernetic Можете ли вы помочь мне понять это утверждение? Что насчет запаха кода?

@psibernetic

Интерфейсы и абстрактные классы дают нам контракт, оба дают нам абстракцию и хорошее определение API. Интерфейсы наиболее полезны при реализации классов, которые могут реализовывать более одного интерфейса или являются подклассами другого базового класса (при условии, что это очень большое преимущество этого базового класса). В частности, в этом случае конкретные классы для Connection, Command и т. Д. Для конкретных поставщиков имеют сильную связь IS A с абстрактными определениями API. Я действительно не могу представить сценарий, когда какому-то разработчику нужно добавить конкретную реализацию для IDbConnection или IConnection в подкласс. Почти единственным сценарием будут новые классы, которые являются производными только для абстрактного класса, и «дублировать» одно и то же определение в интерфейсе - это больше (не нужно) для разработчика API.

Видите ли вы конкретное и конкретное преимущество или сценарий наличия двух равных абстракций? Когда интерфейс действительно дает практическую и реальную пользу _ над абстрактным классом в этом конкретном дизайне API?

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

@eocampo Вы правы в том, что абстрактные классы, вероятно, предоставляют «достаточно хорошую» абстракцию и контракты. Я всегда стараюсь предоставить очень узкие интерфейсы, которые представляют действия, которые можно предпринять, такие как IAsyncCommand и тому подобное. Это позволяет подключать мои фреймворки способами, которые, возможно, не учитывались во время разработки фреймворка, с меньшими шансами на ужасные NotSupportedExceptions или NotImplementedExceptions.

@davkean Запах кода заключается в том, что в большинстве случаев, хотя и не во всех, вам требуется, чтобы разработчик реализовал или унаследовал весь базовый набор функций, которые могут не иметь отношения к делу. Я помню, как видел реализации IDataReader, которые вместо этого читали из кеша или в памяти. Не уверен, что абстрактный класс DbDataReader допускает это, но из названия следует, что нет.

Модель передового опыта, которая использовалась преимущественно в точечной сети, открывала интерфейсы и унаследовала их от базовых классов, не так ли?

Модель передового опыта, которая использовалась преимущественно в точечной сети, открывала интерфейсы и унаследовала их от базовых классов, не так ли?

@psibernetic Ну не всегда. Например, этой рекомендации на сайте MSDN уже более десяти лет. И это правило очень распространено, по крайней мере, из .Net Framework 2.0.

Также это хороший справочник по руководствам по проектированию библиотек в .Net с первых дней:

http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321545613

В любом случае, я думаю, что сейчас здесь идет жесткая дискуссия по двум темам:

a) Интерфейсы предназначены только для обратной совместимости, или мы можем «начать с нуля» (нарушить код), чтобы сделать интерфейс и дизайн API более чистым.
б) Сколько мы можем пойти на современный и чистый дизайн за счет несовместимости с полной структурой .Net. (Совместимость, в частности, между .Net Core и Full core при доступе к данным [не самый низкий уровень и обязательная совместимость])

С моей точки зрения, если у нас есть абстрактные базовые классы в качестве основного и предпочтительного контракта, тогда _interfaces_ должен соответствовать старым только для совместимости. Я понимаю, что @nvivo уже заявил, что после .Net 2.0 официальным контрактом были абстрактные базовые классы, поэтому мы _ могли_ думать, что интерфейсы не решат проблему совместимости, но @mikeobrien также предоставили здесь достоверные данные о зависимости поставщиков на интерфейсах 1.1.

Чтобы прекратить рассылать спам и обсуждать темы здесь, нам нужно будет еще раз прочитать этот длинный разговор, и я не знаю, сможем ли мы согласовать СПИСОК конкретных тем, которые мы рассматриваем, или будет хорошей идеей создать две или три новых вопросы по каждой конкретной теме. Я скорее первый, потому что здесь много хороших моментов. Я не очень хорошо представляю, как мы можем пересчитать все это и убрать некоторый шум (даже мой).

Говоря об интерфейсах, есть ли планы наконец сделать части System.Data универсальными? Меня всегда беспокоило, что System.Data никогда не обновлял свой API за пределами .NET 1.1, в результате чего людям приходилось использовать хаки, такие как метод расширения .AsEnumerable (), чтобы получить IEnumerable.из DataTable. Почему коллекции, такие как DataRowCollection, не были обновлены для реализации универсальных интерфейсов, когда все остальное во фреймворке было обновлено, когда вышла версия 2.0?

Будет ли в нем заглушка System.Data с перенаправлением типов? Мне нужно использовать ODP.NET, но сейчас я не могу.

Создан dotnet / corefx # 7874

@mgravell @ploeh Подразумеваемые классы типов «Rickasaurus» были на горизонте (по крайней мере, для F #, не уверен в C # или .NET в целом https://news.ycombinator.com/threads?id=Rickasaurus). Если дело в том, что они собираются использовать все .NET, решит ли это проблему?

Я не эксперт по Haskell, но, насколько я понимаю, они позволят вам установить простые IDbConnection , IDbConnectionAsync и любые будущие общие интерфейсы постфактум без нарушения исходного кода или бинарная совместимость и без принуждения сторонних поставщиков реализовывать все. Это при сохранении легкости издевательства.

Это правильное понимание? Если да, то есть ли шанс, что эта функция действительно появится в .NET?

Была ли эта страница полезной?
0 / 5 - 0 рейтинги

Смежные вопросы

EgorBo picture EgorBo  ·  3Комментарии

iCodeWebApps picture iCodeWebApps  ·  3Комментарии

chunseoklee picture chunseoklee  ·  3Комментарии

btecu picture btecu  ·  3Комментарии

matty-hall picture matty-hall  ·  3Комментарии