Runtime: Faire des interfaces l'API officielle du fournisseur ADO.NET au lieu des classes

Créé le 26 sept. 2015  ·  174Commentaires  ·  Source: dotnet/runtime

D'après ce que je peux voir actuellement sur la page corefx-progress pour System.Data.Common , les interfaces (IDbCommand, IDbConnection, etc.) ont été supprimées au profit de l'utilisation de classes abstraites.

Mais dans la nouvelle API, la plupart des méthodes principales ne sont ni virtuelles ni abstraites. Sur DbCommand seul, nous pouvons voir ceci :

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();

Bien que ces méthodes puissent certainement être rendues virtuelles ou abstraites, il serait beaucoup plus utile de récupérer les interfaces réelles et de faire dépendre toute API publique de ces interfaces au lieu des classes abstraites.

Ceci est surtout utile lors du développement de bibliothèques. Aujourd'hui, il est très difficile de se moquer d'un lecteur de données pour lui faire renvoyer une valeur spécifique à des fins de test. De même pour s'assurer que ExecuteReaderAsync a été appelé, pas ExecuteReader, etc.

Je propose que l'usine du fournisseur soit plutôt faite comme une interface :

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

Et puis suivez à partir de là vers le reste du fournisseur à des choses comme IDbDataReader , IDbTransaction , etc.

Nous savons que les interfaces sont devenues désynchronisées pour une raison quelconque dans le passé et que les classes abstraites sont devenues l'API officielle, mais cela n'a plus besoin d'être le cas dans corefx.

Notez que cela ne signifie en aucun cas supprimer System.Data.Common, mais faire en sorte que les classes Common implémentent ces interfaces, et vous n'utiliserez pas System.Data.Common à moins que vous n'implémentiez le fournisseur. Les applications dépendraient uniquement des interfaces à la place.

Veuillez considérer ceci pour rendre l'API plus testable sur corefx 1.0.

Lié aux discussions sur dotnet/runtime#14302 et dotnet/runtime#15269.

area-System.Data

Commentaire le plus utile

Nous ne pouvons pas ajouter de membres aux interfaces

Correct, et c'est une _bonne_ fonctionnalité des interfaces. La préférence pour les classes de base abstraites est le moyen le plus sûr d'aider l'entropie de l'API, au lieu de la combattre.

Bien que vous n'ayez pas à suivre les principes d'OOD , je vous suggère de le faire lors de la création d'API OO. En bref, le Principe de Ségrégation d'Interface (ISP) stipule que _aucun client ne devrait être obligé de dépendre de méthodes qu'il n'utilise pas_.

Si vous ajoutez de nouvelles méthodes à une abstraction existante, vous violez automatiquement le FAI.

Vous pouvez décider que vous « n'êtes pas obligé d'adhérer à SOLID » parce que vous êtes Microsoft et que vous travaillez avec la BCL, donc « les règles normales ne s'appliquent pas » (pas de guillemets réels ; il suffit de paraphraser le Contre-arguments).

Ayant maintenu quelques projets open source pendant 6 à 7 ans, d'après mon expérience, il est préférable de garder les interfaces petites. Si vous devez ajouter de nouvelles fonctionnalités à une abstraction, introduisez une nouvelle interface.

Tous les 174 commentaires

Ils seraient passés à des classes de base abstraites car les interfaces ne peuvent pas être versionnées.

Je suppose que les méthodes non virtuelles appellent une autre méthode virtuelle. Les méthodes virtuelles nuisent aux performances, vous ne voulez donc pas rendre les choses virtuelles inutilement.

@JamesNK je vois. Mais avec .NET Core étant une nouvelle API et l'API ADO.NET étant assez stable sur près d'une décennie, pensez-vous que c'est toujours une préoccupation valable ? De plus, en parlant d'accès à la base de données, je suppose que le coût des méthodes virtuelles est éclipsé par le coût de l'accès à la base de données.

@NickCraver , @roji , @FransBouma puisque vous semblez vous intéresser à l'API ADO.NET, avez-vous quelque chose à dire à ce sujet ?

@YoungGah , est-ce quelque chose qui vaut la peine d'être poursuivi ?

Je suppose que les méthodes non virtuelles appellent une autre méthode virtuelle. Les méthodes virtuelles nuisent aux performances, vous ne voulez donc pas rendre les choses virtuelles inutilement.

Lors de l'exécution d'une requête sur une base de données distante et du traitement des résultats, les nanosecondes perdues lors d'un appel virtuel sont négligeables. De plus, ADO.NET utilise ce système depuis le début (comme beaucoup d'autres API dans .NET) et personne ne s'est plaint que leur code DB soit si lent à cause des appels de méthode virtuelle ;)

Je peux voir des méthodes asynchrones dans votre liste, donc je suppose qu'il y a quelques années à peine, MS n'a pas pu ajouter d'async à IDbCommand. Qui sait ce que demain apportera qui nécessitera de nouvelles méthodes ou propriétés.

Les interfaces ne sont pas versionnées.

La performance n'est qu'une des raisons de ne pas rendre quelque chose de virtuel. Réduire la surface des implantations peut-être ? Je vais laisser quelqu'un chez MS dire pourquoi ils ont décidé de ne pas le faire, je ne connais pas grand-chose à ADO.NET donc je spéculerais juste.

@JamesNK Je pense que vos préoccupations sont valables, mais il y a 2 points importants à considérer :

  1. ADO.NET est à peu près stable depuis .NET 2.0, qui une décennie - bien que l'API async ait été ajoutée plus tard, elle n'a pas changé le comportement de l'API, a juste ajouté des homologues asynchrones - je ne vois pas de grands changements dans le paradigme du pilote de base de données bientôt
  2. CoreFx est censé avoir une idée de versionnage différente, car vous pouvez simplement conserver le CLR précédent pour les anciennes applications. Les problèmes de version d'interface ne devraient donc pas avoir un tel impact ici

Considérez également que même un serveur SQL sur "localhost" passera au moins quelques ms juste pour se connecter et renvoyer une requête vide. En pratique, la plupart des requêtes _rapides_ vers les bases de données relationnelles prennent environ 20 ms.

Pouvoir se moquer de l'API avec des outils standard comme NSubstitute ou Moq est aujourd'hui beaucoup plus précieux pour le développeur que d'économiser des microsecondes dans les recherches de méthodes virtuelles.

Je suppose que je n'ai pas d'opinion très tranchée ici, mais voici quelques remarques :

  • D'accord avec ce qui précède, la suppression du virtuel par rapport au non-virtuel est négligeable dans une API pour l'accès à la base de données
  • Les classes de base permettent à ADO.NET de fournir des implémentations, je suppose que c'est le sujet de la plupart des méthodes non virtuelles non abstraites - la surcharge d'ExecuteReader qui n'accepte pas un CommandBehavior passe CommandBehavior.Default à la surcharge ça le fait. Si vous passez aux interfaces, chaque fournisseur devra implémenter ExecuteReader() avec exactement le même passe-partout...
  • Je ne suis pas sûr que cela soit valable dans tous les principaux frameworks de moquerie, mais au moins dans Moq, n'est-il pas aussi facile de se moquer d'une classe de base que d'une interface ?

Donc, dans l'ensemble, l'idée de supprimer les classes de base ou les interfaces semble bonne (plus simple). Étant donné que je ne vois aucun avantage aux interfaces (à moins que je ne me trompe sur la facilité de se moquer), et que les classes de base peuvent fournir des fonctionnalités communes (c'est-à-dire les méthodes non virtuelles non abstraites), je suppose que l'approche de Microsoft consistant à vider les interfaces ça me parait bien...

Je suis d'accord avec @roji sur tous ses points.

@roji juste une note, je ne propose pas de supprimer les classes de base, je propose d'ajouter les interfaces comme API par défaut. Les classes de base peuvent toujours implémenter le comportement par défaut.

En ce qui concerne les tests, j'ai eu d'énormes problèmes pour tester si mon API appelait les bonnes méthodes. Pour vérifier si ExecuteDataReader a reçu les bons paramètres par exemple, vous devez vérifier une autre méthode protégée qui est appelée en interne avec des paramètres différents. C'est loin d'être idéal.

Actuellement, sauf erreur, le seul framework qui peut se moquer de l'API ADO.NET est le framework MS Fakes qui peut se moquer d'absolument n'importe quoi en interceptant les appels. Moq et les autres ne peuvent pas faire ça.

Je suis curieux de voir si d'autres personnes ont eu des problèmes similaires.

@roji juste une note, je ne propose pas de supprimer les classes de base, je propose d'ajouter les interfaces comme API par défaut. Les classes de base peuvent toujours implémenter le comportement par défaut.

Désolé, j'ai mal compris. Dans ce cas, votre proposition ne garde-t-elle pas plus ou moins les choses telles qu'elles sont dans .NET (pas qu'il y ait quelque chose de mal à cela) ?

En ce qui concerne les tests, j'ai eu d'énormes problèmes pour tester si mon API appelait les bonnes méthodes. Pour vérifier si ExecuteDataReader a reçu les bons paramètres par exemple, vous devez vérifier une autre méthode protégée qui est appelée en interne avec des paramètres différents. C'est loin d'être idéal.

Si je comprends votre scénario (pas sûr), le CallBase Moq est utile pour ce genre de scénario - les implémentations par défaut sont héritées de la classe de base

@roji

votre proposition ne garde-t-elle pas plus ou moins les choses telles qu'elles sont dans .NET (ce n'est pas qu'il y ait quelque chose de mal à cela) ?

Pas exactement. L'API d'interface a été ajoutée dans .NET 1.0 et obsolète sur 2.0. Depuis 2.0, les interfaces sont là pour la compatibilité, mais il n'y a pas d'interface pour ProviderFactory ou d'autres classes dans Data.Common. Il n'y a également rien pour l'API async ou les méthodes 2.0 ou plus récentes.

Moq ne peut se moquer que des choses moqueuses. Il doit y avoir une méthode virtuelle ou abstraite qu'elle peut remplacer, ou une méthode protégée qu'elle peut appeler. L'API actuelle fournit une méthode pour certains cas, mais pas pour la plupart d'entre eux. Il y a beaucoup de choses qui sont internes, privées et hors de portée à moins que vous n'utilisiez la réflexion. Seul MS Fakes peut le faire car il remplace la référence par une cale, mais cela n'est disponible que sur VS Enterprise et inutile pour les projets open source.

Il semble que j'ai un cas très spécifique, mais certainement tous ceux qui ont déjà essayé de se moquer de cette API ont rencontré ce problème. Juste google, presque toutes les solutions se terminent par "se moquer de l'API d'interface héritée ou créer un wrapper dont vous pouvez vous moquer":

@nvivo OK, merci pour les détails supplémentaires - j'admets que je ne suis pas allé très loin en me moquant d'ADO.NET.

La chose que je ne comprends pas, c'est pourquoi vous voudriez vous moquer des méthodes internes, privées et autrement hors de portée d'une API. Ne devriez-vous pas vous moquer des méthodes publiques qui sont directement disponibles pour votre propre code d'application (ce que vous essayez de tester) ? Je vois le problème avec les méthodes non virtuelles (par exemple, la surcharge ExecuteReader() à 0 paramètre), mais étant donné que dans ADO.NET, celles-ci appellent toujours (?) Une surcharge virtuelle (par exemple, ExecuteReader(CommandBehavior)), existe-t-il un vrai problème ici?

Essayant juste de comprendre votre scénario de problème, pouvez-vous donner un exemple simple ?

@nvivo Nous n'avons actuellement aucun plan pour apporter des interfaces en raison du problème de versionnage qui a déjà été signalé par plusieurs personnes sur ce fil. Un bon exemple d'interfaces en retard est l'ajout de méthodes asynchrone et de streaming dans .NET Framework 4.5. Lorsque nous avons ajouté ces nouvelles fonctionnalités, nous avons soigneusement examiné l'extension des interfaces. Les options que nous avions à l'époque étaient soit de fournir InterfaceFooV2 ou des interfaces séparées pour l'asyn et le streaming. Nous ne voulions pas ajouter InterfaceFooV2 car nous pouvons prévoir que nous voudrions ajouter plus d'API à l'avenir. Continuer à ajouter des interfaces distinctes pour chaque nouvelle fonctionnalité serait déroutant car elles ne sont pas liées aux interfaces existantes.

@roji J'ai eu des cas où je veux m'assurer qu'une surcharge spécifique d'ExecuteReader a été appelée, et non que "l'une des surcharges". C'est le genre de chose que vous n'avez que dans les bibliothèques, pas sur le code utilisateur.

@YoungGah merci pour l'info. Je ferme ça alors.

Les personnes responsables de ce changement ont-elles une idée de son effet ? Les interfaces ADO.NET de base existent depuis plus d'une décennie et l'accès aux données étant au centre de la plupart des applications professionnelles, j'ai du mal à comprendre comment ne pas casser délibérément autant de bases de code existantes n'est pas la priorité absolue ? Ce sont quelques-unes des interfaces de haut niveau les plus critiques de .NET, supprimant ces ruptures de chaque bibliothèque d'accès aux données ADO .NET et par conséquent de chaque projet l'utilisant. Les supprimer crée une fragmentation artificielle, provoquant frustration et confusion qui entraveront l'adoption de CoreCLR.

Vous pouvez toujours versionner les interfaces et les rendre compatibles avec la source en ajoutant simplement des méthodes d'extension pour toute nouvelle API hors IDbCommand , par exemple :

public interface IDbCommand
{
    //...
}

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

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

L'interface principale de IDbCommand ne doit jamais changer après la sortie de DNX et vous pouvez continuer à ajouter des fonctionnalités avec la stratégie ci-dessus. Vous pouvez également plus tard (dans une version de rupture majeure), regrouper ces extensions et les fusionner dans l'interface principale. Dans tous les cas, nous obtenons les interfaces ADO.NET de base stables, essentielles à la migration des bases de code existantes et, par conséquent, à l'adoption de CoreCLR.

@davkean m'a demandé de fournir des exemples concrets de l'impact qu'aura la suppression des interfaces ADO .NET de base. Je ne peux pas imaginer que ce changement ait été envisagé sans évaluer l'impact incommensurable qu'il aurait sur l'écosystème .NET existant, mais encore une fois, cela a également été fait, il est donc possible qu'il n'ait pas été envisagé - ce que je vais supposer ici - ce n'était pas le cas.

Malgré le rôle d'EF en tant qu'ORM par défaut de .NET et son succès exceptionnel à capturer une grande majorité de parts de marché, il existe toujours une grande population de développeurs .NET qui préfèrent utiliser des ORM alternatifs pour un certain nombre de raisons différentes. Par exemple, une caractéristique importante en ce qui concerne CoreCLR est qu'ils ont un support de première classe s'exécutant sur Mono/Linux/OSX ainsi que plusieurs SGBDR alternatifs. Puisque CoreCLR se positionne fortement pour le marché des développeurs Linux/OSX, plus il y a de support pour les RDBM alternatifs, mieux c'est. Un autre trait important de la population de développeurs qui adoptent les micro ORM est qu'ils ont évalué en dehors des paramètres par défaut de l'écosystème MS pour choisir l'ORM qui leur convient le mieux. D'après tout ce que j'ai vu, il existe une forte corrélation entre les développeurs .NET OSS actifs (c'est-à-dire anti-matière noire) et les développeurs qui adoptent les micro ORM, de même je m'attends à ce que cela ait une forte corrélation avec les premiers utilisateurs de CoreCLR - dont la proposition de valeur majeure est développer sur OSX/Linux. Ce sont quelques-unes des raisons pour lesquelles il serait avantageux d'inclure l'écosystème .NET environnant dans votre prise de décision lorsque vous faites des choix de conception fondamentaux comme celui-ci.

Téléchargements ORM alternatifs

Un coup d'œil rapide aux téléchargements NuGet fournit une indication de ce à quoi ressemble la part de marché non-EF :

Hibernation - 1M+
Pimpant - 1M+
OrmLite - 500k+
Simple.Données - 300k+
PetaPoco - ~100k
NPoco - 30k+

Les vrais chiffres sont bien plus que cela, car de nombreux Micro ORM comme Dapper, Massive, PetaPoco, NPoco, etc. ont été conçus pour tenir dans un seul fichier .cs, de sorte que NuGet ne signale pas sa véritable utilisation. Il existe également des ORM à source fermée comme LLBLGen Pro qui ont une grande base d'utilisateurs mais son utilisation n'est pas signalée par NuGet, de même, je suis sûr que j'ai raté un certain nombre d'autres ORM que j'ai oubliés / dont je ne connais pas.

Impact sur les ORM alternatifs

Grâce à GitHub, nous pouvons effectuer une recherche rapide pour voir combien de fichiers sources différents contiennent le noyau
IDbConnection interfaces IDbCommand et IDataReader ADO .NET impactées par ce changement :

IDbConnexionIDbCommandeIDataReader
Hibernation59181132
Pimpant172117
OrmLite1795426
Données.simples29276
NPoco4dix3

Remarque : ces résultats ne montrent que les fichiers sources, le nombre réel de références cassées est beaucoup plus élevé.

Impact sur le code source du client

L'impact réel de ce changement s'étend également à toutes les dépendances de projets utilisant ces ORM.
Malheureusement, l'effet ne se limite pas aux implémentations internes car il casse également le client
le code source car de nombreux Micro ORM ne sont que des méthodes d'extension sur les interfaces ADO.NET afin que le client
le code ressemble à :

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"));

Une caractéristique d'extensibilité de l'utilisation de méthodes d'extension est que ces ORM sont "ouverts" et que les clients peuvent étendre les ORM avec leurs propres API de première classe en ajoutant des méthodes d'extension dans leurs propres projets - celles-ci sont également cassées.

De toute évidence, tout code source qui transmet IDbConnection est désormais également interdit de fonctionner sur CoreCLR.

Par exemple, les interfaces ADO.NET de base sont largement utilisées dans des frameworks de haut niveau comme ServiceStack, adoptés car il s'agit de la dépendance minimale pour permettre l'accès aux données multi-SGBDR. Il a également été supposé que parmi toutes les classes qui étaient peu susceptibles de changer, il s'agirait des interfaces ADO.NET de base.

Sommaire

Je suis personnellement étonné qu'il y ait jamais eu un avenir dans .NET sans ces interfaces.
Les interfaces sont par conception spécifiques pour permettre plusieurs implémentations et ADO.NET en est une
des "modèles de fournisseur ouvert" les plus importants dans .NET. Je n'ai aucune idée des priorités qui ont entraîné la suppression de ces interfaces, mais les bases de code .NET existantes massives qui reposent sur ces interfaces ainsi que l'écosystème alternatif EF .NET devraient recevoir une priorité beaucoup plus élevée. Cela provoque une perturbation importante et constitue un obstacle majeur requis pour prendre en charge à la fois les plates-formes .NET 4.x et CoreCLR existantes, forçant une quantité non négligeable de complexité supplémentaire qui doit être appliquée à toutes les bases de code existantes affectées par cela.

La perception actuelle est qu'ADO.NET/CoreCLR est en train d'être repensé pour fournir un support de première classe pour EF et SQL Server sans tenir compte du reste de l'écosystème - des décisions de rupture non transparentes comme celle-ci ne font que renforcer ce stéréotype .

En tant qu'ancien membre de l'équipe .NET (je travaille maintenant sur Roslyn), j'ai été fortement impliqué dans la conception originale des nouvelles données communes, avec les équipes SQL et Entity Framework. Je n'y suis pas impliqué pour le moment, mais je peux ajouter un peu de contexte pour aider à corriger certaines des déclarations que je vois sur Twitter et au-dessus.

La conception actuelle de System.Data.Common pour .NET Core a commencé en décembre 2012, environ 2 ans avant notre ouverture.

Buts:

  • Concevoir une surface moderne pour .NET Core, qui réduit la duplication des concepts ( IDbConnection vs DbConnection ), les confusions, les erreurs et les problèmes de superposition (diviser SqlClient de DataCommon, séparer DataSet des abstractions de base) de la conception originale de .NET 1.0. Un qui serait facilement repris, à la fois par les consommateurs existants et les _nouveaux_ développeurs de .NET Framework.
  • Autorisez les fournisseurs et les consommateurs à créer un seul binaire/source sur .NET Core, puis exécutez ce même binaire sur .NET Framework. Notez que l'inverse n'était pas un objectif ; être capable de prendre le binaire/la source .NET Framework et de l'exécuter sans quelques modifications sur .NET Core.

Correction de quelques choses qui se répandent :

  • Les interfaces telles qu'elles sont ne sont pas versionnables. Nous ne pouvons pas ajouter de membres aux interfaces, et la proposition ci-dessus fournie par @mythz via des méthodes d'extension nécessite de toute façon que les fournisseurs dérivent des classes de base abstraites.
  • System.Data.Common _ne_ s'est pas_ éloigné du modèle de fournisseur. Les interfaces ont été supprimées car il s'agissait d'un concept .NET 1.0 hérité qui a été remplacé/dupliqué par les classes de base abstraites introduites dans .NET 2.0. Au moment où nous avons pris cette décision, chaque fournisseur que nous pouvions trouver était dérivé des classes de base.
  • Comme les interfaces, les classes de base sont moquables.
  • Nous avons compris que certains changements seraient nécessaires pour ceux qui utilisent les interfaces .NET 1.0, cependant, il s'agit d'un port très simple à déplacer vers les classes de base. Par exemple, consultez ces quelques lignes de modification pour AutoMapper : (https://github.com/AutoMapper/AutoMapper.Data/blob/master/AutoMapper.Data/DataReaderMapper.cs#L14).

Quelque chose que j'ai du mal à comprendre :

Nous ne pouvons pas ajouter de membres aux interfaces

Comment n'est-il pas encore possible d'ajouter des membres aux interfaces CoreCLR, c'est bien de les arracher entièrement ?

la proposition ci-dessus fournie par @mythz via des méthodes d'extension nécessite que les fournisseurs dérivent de toute façon des classes de base abstraites.

L'important est que les interfaces existent et permettent la compilation du code source qui les référence.

Si vous ne voulez pas versionner les interfaces, corrigez-les EOL, restaurez simplement les interfaces telles qu'elles étaient avant qu'elles ne soient arrachées et atténuez la charge désormais imposée à toutes les autres bibliothèques qui les utilisent. Je veux dire que ces interfaces de base n'ont jamais été obsolètes sans aucun avertissement ou chemin de migration fourni. Pourtant, nous sommes punis pour avoir adopté une API publiée, bien connue et stable en tant que partie intégrante de nos bibliothèques ?

c'est un portage très simple à déplacer vers les classes de base.

Cela doit être ajouté sur chaque fichier source qui référence les interfaces ADO.NET et oblige les clients à salir leur code avec des symboles de construction personnalisés.

Il ne semble pas que la compatibilité descendante soit la même ici, mais casser délibérément les clients existants dans une future version n'est tout simplement pas une option (je suis surpris que cela soit même envisagé avec la part de marché beaucoup plus importante d'ADO .NET). Nous ne pouvons pas casser les clients 4.x existants et pourtant on nous demande de prendre en charge CoreCLR. Devrions-nous également dupliquer des documents/exemples ?

Comment n'est-il pas encore possible d'ajouter des membres aux interfaces CoreCLR, c'est bien de les arracher entièrement ?

La surface dans .NET Core doit être binairement compatible avec .NET Framework pour permettre aux premiers et aux tiers de s'appuyer sur .NET Core et d'exécuter la portabilité sans modifications sur .NET Framework. L'ajout de membres aux interfaces enfreint cela, car les consommateurs de ces membres échoueraient lorsqu'ils s'exécutaient sur .NET Framework.

Je ne plaide pas pour la suppression ou l'ajout de ces interfaces, je voulais juste ajouter un peu de contexte pour expliquer pourquoi la conception s'est retrouvée là où elle se trouve. Je laisserai les propriétaires actuels, y compris @YoungGah et @saurabh500, s'attaquer à cela.

Juste pour résumer le fil, la raison pour laquelle vous pensez que Microsoft devrait porter ces interfaces, est de permettre à l'écosystème de se porter facilement vers .NET Core, tout en conservant leurs implémentations .NET Framework ?

est de permettre à l'écosystème de se porter facilement vers .NET Core, tout en conservant ses implémentations .NET Framework ?

Oui.

Juste pour résumer le fil, la raison pour laquelle vous pensez que Microsoft devrait porter ces interfaces, est de permettre à l'écosystème de se porter facilement vers .NET Core, tout en conservant leurs implémentations .NET Framework ?

Oui. Les API externes sont désormais cassées si je porte ma base de code (LLBLGen Pro) vers corefx : je dois alors exposer 2 apis ou casser la base de code existante pour tous mes utilisateurs.

Ce serait peut-être bien pour vous de casser nos affaires car vous ne ressentez pas la douleur, nous le faisons. Cela ne me convient pas : je dois soit vivre avec une base de code massacrée et maintenir 2 API qui font la même chose, OU casser le code de mes utilisateurs parce que vous pensiez que c'était OK.

Je ne comprends pas non plus pourquoi les interfaces ne sont pas versionnées, c'est juste une interface, comme une classe a aussi une interface. CoreFX peut parfaitement ajouter les méthodes asynchrones aux interfaces.

La surface dans .NET Core doit être binairement compatible avec .NET Framework pour permettre aux premiers et aux tiers de s'appuyer sur .NET Core et d'exécuter la portabilité sans modifications sur .NET Framework. L'ajout de membres aux interfaces enfreint cela, car les consommateurs de ces membres échoueraient lorsqu'ils s'exécutaient sur .NET Framework.

Solution simple : ajoutez les interfaces telles qu'elles sont actuellement. Et une fois que vous avez tous compris que cette règle ci-dessus est en fait plutôt stupide, vous pouvez ajouter les méthodes dont vous aviez besoin pour ajouter aux interfaces il y a longtemps aux interfaces et passer à autre chose.

Je travaille avec un logiciel MS assez longtemps pour que des règles comme celle ci-dessus soient excellentes sur le papier, mais en pratique, elles sont enfreintes à la seconde où une équipe MS importante a besoin qu'elles soient enfreintes. Si vous êtes si «ouvert» et «différent» que vous le dites dans le hoopla marketing/pr de CoreFX, montrez-le. Tout ce que je vois en ce qui concerne System.Data et CoreFX, c'est "ce dont MS a besoin, ce dont tout le monde a besoin est mis en veilleuse ou ignoré".

Une autre chose que j'ai oublié de mentionner : Fowler a mentionné hier sur Twitter que vous avez besoin que tout le monde porte ses affaires. Je dois payer moi-même le portage de ma base de code LoC 500K vers CoreFX, cela prend du temps, des efforts et prendra du temps pour d'autres fonctionnalités. Une friction supplémentaire totalement artificielle (c'est une nouvelle plate-forme ! Comment peut-il y avoir des règles restrictives ?) n'aide vraiment pas du tout : cela ajoute des coûts de maintenance supplémentaires, prend plus de temps pour porter le code et tester et donne un fardeau supplémentaire à nos utilisateurs.

Tout cela est hors de votre portée, et ne vous concerne pas, semble-t-il. Mais vous oubliez une chose : et _si_ nous ne portons pas notre code et avec moi plus de monde ? Je suis prêt à investir du temps et donc mon propre argent pour porter ma grande base de code sur votre nouveau framework brillant, mais désolé de le dire, chaque fois que je rencontre un problème, je rencontre des restrictions, des règles étranges et des débats sans fin se terminant dans le silence . Iow : Je me sens vraiment laissé seul alors qu'en même temps, vous semblez si désespérément vouloir que nous aimions votre nouveau cadre brillant.

Comme je l'ai dit il y a longtemps : Vendez-moi ce framework, ce nouveau CoreFX. Eh bien, garder la friction et introduire beaucoup de fromage déplacé et emporté ne crée pas une grande incitation à investir beaucoup de temps (et d'argent) dans cela.

Juste mes 2 cents.

@FransBouma S'il

Je ne plaide pas pour ou contre l'ajout des interfaces. Cependant, il n'est pas compatible d'ajouter des méthodes aux interfaces. Parcourons ceci :

1) Ajouter IDbConnection.OpenAsync à .NET Core
2) Toute personne qui appelle cette méthode ne pourra plus s'exécuter sur .NET Framework (enfreignant un principe/objectif de base que j'ai appelé ci-dessus). Cela brise également le concepteur XAML et quelques autres fonctionnalités VS qui reposent sur ce fait même.
3) Pour mettre .NET Framework à jour, nous livrons une nouvelle version de .NET Framework "4.7" avec IDbConnection.OpenAsync
4) Chaque type qui a implémenté IDbConnection avant d'ajouter cette méthode ne parvient plus à se charger sur .NET Framework "4.7"

C'est pourquoi nous ne pouvons pas ajouter de méthodes aux interfaces.

Si je garde ma frustration quant à la façon dont les choses se passent en ce qui concerne la communication des problèmes de SP, vous ne le saurez pas tous et penserez que tout est rose et arc-en-ciel. Si cela ne semble pas professionnel, qu'il en soit ainsi, je ne me soucie plus de savoir si MS pense que je suis un professionnel ou non.

Cela dit : je ne suis pas marié aux interfaces, donc si elles disparaissent, le fait qu'à partir de là il y ait des classes et aucune interface avec laquelle travailler en théorie ne fera pas de moi un triste panda : ce qu'il faut faire peut être fait en théorie à travers les classes de base aussi, aujourd'hui, comme aujourd'hui tous les principaux fournisseurs ADO.NET jouent bien et dérivent des classes de base (cela n'a pas été le cas dans le passé IIRC avec ODP.NET implémentant une interface mais pas dérivant de la classe de base). C'est aussi la raison pour laquelle j'ai commencé plus tôt dans ce fil de discussion, je ne pensais pas vraiment que les supprimer était un gros problème. Depuis lors, j'ai eu le temps d'y réfléchir et je pense que c'est un gros problème.

Nous ne vivons pas dans le vide sur Mars, et les middleware/frameworks au bas de la pile ont maintenant un problème : les utilisateurs des versions complètes .NET actuelles de ces frameworks veulent continuer à les utiliser sur CoreFX car ils connaissent ces frameworks. Les porter sur CoreFX est cependant un gros PITA, pour une myriade de raisons, l'une d'entre elles étant des interfaces souvent utilisées exposées dans des API publiques n'étant pas présentes sur CoreFX (et la raison de ce fil).

Pour cette seule raison, j'aimerais revoir les interfaces. Pour moi personnellement pas pour des raisons techniques (par exemple, async a besoin de classes de base, c'est déjà le bordel). Je sais qu'il leur manque certaines méthodes, mais c'est votre problème, pas le mien. Les supprimer en fait mon problème et (en paraphrasant maintenant) la réponse de MS à cela est: levez les mains avec "ne peut pas être fait!". Mais je n'ai pas ce luxe. Vous avez créé ce gâchis, vous le résolvez. Vous voulez que je porte mon code, que j'investisse beaucoup de temps et d'argent (que je dois payer moi-même) pour supporter votre nouveau framework, pourquoi faites-vous alors _votre_ problème _mon_ problème ?

En regardant votre scénario en 4 étapes : l'ajout de méthodes aux interfaces n'est pas un problème SI vous voyez CoreFX comme un framework séparé. Et n'est-ce pas le cas de toute façon ? C'est la même chose qu'avec Compact Framework il y a toutes ces années (sur lequel j'ai porté mon framework, et j'ai appris quelques leçons difficiles alors qui me disent que le portage vers CoreFX ne sera pas simple, rapide et facile et garder deux bases de code ne le fera pas non plus): nous commençons avec 1 API, puis quelqu'un a oublié quelque chose ou une équipe au sein de MS a besoin de quelque chose, et viole un changement de rupture que seuls une poignée de développeurs de pile de bas niveau rencontreront et ainsi de suite et les deux routes se sépareront.

(exemple: Compact Framework a oublié 'SerializableAttribute'. Ils ont ajouté cela avec un attribut factice ne faisant rien dans une version ultérieure, mais qui a cassé le code qui anticipait que celui-ci n'était pas présent et qui définissait le leur)

Diviser les routes est cependant compréhensible : essayer de garder les choses compatibles est trop restrictif. Je prédis ici maintenant que cette règle sera brisée à l'avenir.

Voir les choses comme "compatibles" est important non seulement au niveau de la signature de l'API, mais également au niveau du comportement de l'API. Croire que ces deux seront complètement identiques (CoreFX et .NET Full) dans le comportement de l'API est trop risqué : un développeur de framework devra tester la même fonctionnalité sur CoreFX et sur .NET full, il n'y a aucun moyen de tester sur CoreFX seul. assez pour supposer que le code fonctionne à 100% de la même manière sur .NET complet à l'avenir : car comment pouvez-vous garantir cela ? Une pile d'appels de 20 appels en profondeur sur CoreFX a touché tellement d'autre code que sur .NET full, un petit détail ici et là et les choses changent.

Le point dans tout cela est : c'est un framework séparé : le code compilé avec CoreFX peut être différent du code compilé avec .NET full.

Il y a quelques situations :

1) un framework a une base de code dont 100% compile sur CoreFX. Cela donne une dll qui est exécutable sur .NET full
2) un framework a une base de code dont 70% compile sur CoreFX et 100% sur .NET full. Cela donne 2 DLL : une pour CoreFX et une pour .NET full. Il est idiot d'exécuter la version CoreFX sur .NET complet, car il manque 30% des fonctionnalités.

Dans le cas de 1) je comprends votre point. Dans le cas de 2) (ce qui est le cas pour tous les frameworks de ciblage complet .NET actuels, parmi lesquels _tous_ les ORM tiers), votre argument n'a vraiment aucun sens, car ils devront de toute façon fonctionner avec 2 dll : en fait 2 bases de code qui doivent être maintenus séparément, testés séparément et migrés séparément vers leurs propres nouvelles versions. Surtout si CoreFX obtient de nouvelles fonctionnalités qui ne font pas encore partie de .NET full (ce qui sera le cas). (btw: si vous ajoutez DbDataReader.GetSchemaTable() à CoreFX qui renvoie une structure de données différente de celle d'un DataTable, car MS refuse de le porter, le code utilisant DbDataReader.GetSchemaTable sur CoreFX se brisera également sur .NET full. Si vous le nommez différemment il se brisera aussi bien que la méthode n'est pas là. Iow: le code se brisera si des choses qui ne sont pas dans _les deux_ frameworks sont utilisées. Cela ne veut pas dire que les choses ne devraient pas être présentes dans CoreFX).

Ne pas avoir d'interfaces sur CoreFX rend la situation du framework dans la situation 2) persistante : ils ne peuvent pas bouger pour devenir un framework qui s'intègre dans 1) car par exemple leur API expose les interfaces.

Microsoft réécrit ses propres trucs pour que leurs frameworks deviennent des frameworks dans la situation 1), c'est cool, mais nous n'avons pas un budget d'un million de dollars, plus de 15 personnes sur l'environnement d'exécution ORM et une grosse machine de relations publiques de notre côté qui va lisser les rides de casser toutes les applications là-bas. Nous sommes donc soit coincés dans 2), soit avons besoin d'un peu d'aide de MS pour passer à 1).

C'est ce qui est en jeu ici. Vous avez dit sur twitter "dites-nous ce dont vous avez besoin". Nous faisions. À plusieurs reprises. Surtout en ce qui concerne System.Data, il n'y a pas de communication. Rien. Pas de plans futurs, pas de discussion sur ce qu'il faut faire, juste des impasses et parfois si une personne atteinte de SEP intervient, c'est une personne qui n'a aucun intérêt réel dans la question. J'apprécie le temps que vous y consacrez, plus nous avons d'expérience, mieux c'est, mais en même temps, c'est comme en parler à un collègue : ça ne sera pas résolu parce que la ou les personnes en charge sont absentes et non participer à la discussion.

Si cela me fait paraître frustré et que Dieu nous en préserve « non professionnel », alors qu'il en soit ainsi.

Merci pour l'écoute. Au fait, je ne me fais pas d'illusions par rapport à System.Data : ce sera le naufrage d'une API vers laquelle porter le code et comme il n'y a aucune communication entre les personnes en charge des développeurs qui écrivent des frameworks clés au-dessus de leur API, il y a peu ou pas d'espoir. changera. Ce n'est pas de ta faute, @davkean , ce n'est rien de personnel.

Je dois faire écho aux frustrations ci-dessus concernant le manque de communication. Nous avons également besoin d'insertions en bloc et d'informations de schéma. Il n'y a eu aucune avancée ou communication depuis plus d'un mois (voir dotnet/runtime#15269 et dotnet/runtime#14302) de ces fonctionnalités de base manquantes (dans les deux sens). Pourtant, Microsoft qualifie le code actuel de "candidat à la publication", ce qui lui-même est un message de "c'est assez bon". Ce n'est pas. Il manque des éléments essentiels qui doivent être ajoutés et si vous suivez ces fils de discussion, vous devez être dans la première version pour des raisons de versionnement similaires.

Regardez la dernière mise à jour sur dotnet/runtime#14302 ("Pourquoi DataTable/View/Set Absent ?"), elle date de 22 jours en demandant :

Donc, System.Data.Common est-il désormais complet pour la V1 de CoreCLR ?

Oui, la frustration peut paraître non professionnelle. Le ton et le contexte du texte sont nuls et l'ont toujours été, mais c'est à cela que nous sommes limités ici. Je pense que tout le monde essaie d'être productif ici, mais nous recevons un peu d'obstruction du côté de CoreFX sur les progrès réels dans le domaine des System.Data et c'est, pour être franc, exaspérant à la fois en tant qu'auteur de bibliothèque et un utilisateur de ces bits.

Nous avons besoin de ces éléments fonctionnels de base, interfaces ou non - je ne suis pas un inconditionnel des interfaces et nous avons porté Dapper sans elles. Mais l'absence de DataTable, d'informations sur le schéma de résultat, d'insertion en bloc et autres sont inacceptables dans une "release candidate". Microsoft est celui qui augmente la frustration d'étiqueter le code actuel comme RC alors qu'il est presque universellement convenu qu'il n'est pas prêt à être publié. Oui, ce n'est qu'une étiquette, mais c'est à la fois une étiquette incorrecte et une qui augmente considérablement le niveau d'urgence car elle est basée sur un calendrier arbitraire (qui aurait dû changer pour refléter la réalité). Je ne pense pas que quiconque dans ce fil soit responsable de ce calendrier, mais cela vaut la peine de le mentionner comme un facteur majeur de la frustration _level_.

Revenons à la racine du problème. Nous avons besoin de ces éléments, et nombre de nos millions d'utilisateurs en ont besoin. Alors corrigeons-le.

N'oublions pas NHibernate avec plus de 1M de téléchargements :

| IDbConnexion | IDbCommande | IDataReader |
| --- | --- | --- |
| 59 | 181 | 132 |

La perception actuelle est qu'ADO.NET/CoreCLR est en train d'être repensé pour fournir un support de première classe pour EF et SQL Server sans tenir compte du reste de l'écosystème - des décisions de rupture non transparentes comme celle-ci ne font que renforcer ce stéréotype .

Cette perception est renforcée par des choses comme celle-ci : https://github.com/dotnet/corefx/issues/4646

Pour autant que je sache, il n'y a aucun moyen d'implémenter cette API de manière utile en dehors de l'assembly SqlClient.

Je suis actuellement d'accord avec les tests sans interfaces. Mais honnêtement, je ne comprends pas le raisonnement avec le versioning et la compatibilité de l'interface.

L'idée de .NET Core n'est-elle pas qu'il s'agit d'un nouveau framework sans le fardeau de la compatibilité et qu'il est fourni avec votre application, vous n'avez donc pas à faire face à de tels problèmes ? Le fournisseur est déjà incompatible avec ceux de .NET en raison du manque de choses comme les schémas et les tables de données, alors avec quoi romprait-il la compatibilité ? Si l'interface change, il suffit de compiler avec la nouvelle version et de la regrouper avec votre application.

Il semble que la plupart des excuses pour la conception ne soient que des soucis de l'ancien cadre qui ne s'appliquent pas au nouveau. Quoi qu'il en soit, voyons comment cela se passe dans la pratique.

Pour les utilisateurs qui ont l'intention de prendre en charge plusieurs frameworks et qui ont historiquement ciblé les interfaces... Je veux juste partager un tas de laids que Dapper utilise; Je ne dis pas que c'est _bon_, mais c'est suffisant pour le faire compiler. Bien sûr, il est dupliqué dans une énorme pile de fichiers... Je partage principalement ceci pour souligner encore un autre des impacts :

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

Nous ne pouvons pas ajouter de membres aux interfaces

Correct, et c'est une _bonne_ fonctionnalité des interfaces. La préférence pour les classes de base abstraites est le moyen le plus sûr d'aider l'entropie de l'API, au lieu de la combattre.

Bien que vous n'ayez pas à suivre les principes d'OOD , je vous suggère de le faire lors de la création d'API OO. En bref, le Principe de Ségrégation d'Interface (ISP) stipule que _aucun client ne devrait être obligé de dépendre de méthodes qu'il n'utilise pas_.

Si vous ajoutez de nouvelles méthodes à une abstraction existante, vous violez automatiquement le FAI.

Vous pouvez décider que vous « n'êtes pas obligé d'adhérer à SOLID » parce que vous êtes Microsoft et que vous travaillez avec la BCL, donc « les règles normales ne s'appliquent pas » (pas de guillemets réels ; il suffit de paraphraser le Contre-arguments).

Ayant maintenu quelques projets open source pendant 6 à 7 ans, d'après mon expérience, il est préférable de garder les interfaces petites. Si vous devez ajouter de nouvelles fonctionnalités à une abstraction, introduisez une nouvelle interface.

S'il y avait eu des votes positifs ici, j'aurais voté pour le commentaire de

Commentaire perspicace de @ploeh comme d'habitude.

@FransBouma , nous
@NickCraver , SqlBulkCopy est dans notre futur plan et nous travaillons sur le schéma. Nous sommes lents à progresser sur le schéma car nous devons également faire des progrès raisonnables pour que notre pile fonctionne sur la plate-forme x.
@mythz , merci d'avoir fourni les exemples, les chiffres et l'évaluation de l'impact sur les clients. Nous les passerons en revue.

@YoungGah Veuillez mettre à jour les problèmes liés aux informations afin que ces problèmes restent à jour, par exemple https://github.com/dotnet/corefx/issues/1039 , sinon les informations clairsemées sont dispersées tout autour. C'est bien que vous ajoutiez GetSchemaTable (et l'équivalent de DbConnection, ne l'oubliez pas !), mais il est si difficile d'obtenir des informations sur ce qui se passera et _quand_. Y a-t-il un plan sur ce qui sera ajouté quand ? Tout ce que nous avons à faire maintenant, c'est un indice que dans « l'avenir », quelque chose pourrait être ajouté. Ce n'est pas vraiment génial pour planifier un portage d'une base de code, pour être honnête.

@FransBouma , oui, je

Que se passe-t-il ici, et pour référence future @YoungGah; IDataReader a une dépendance sur DataTable, qui a une dépendance sur DataSet (que nous considérons comme une couche distincte - car il est lourd de politique, contrairement à ces types qui sont sans politique), il y a donc un travail de conception ici pour casser cela si ces interfaces étaient jamais rapporté.

Je placerais un autre vote ici pour l' approche de @davkean sur le découplage et de la gestion des versions.

Pourquoi ne pouvez-vous pas simplement avoir une nouvelle interface héritant de l'ancienne. Obsolète l'ancienne. Supprimez l'ancien à l'avenir. Au moins alors vous pouvez l'étendre et ne pas casser les usages existants.

Ou plusieurs interfaces plus petites. Je viens juste de commenter ploehs.

Je ne comprends pas ce besoin d'avoir une compatibilité parfaite avec le .NET d'origine. Il n'y a rien à rompre ici, il s'agit d'un nouveau framework et de l'occasion idéale de rompre les liens avec le code hérité et d'appliquer des modifications qui sont nécessaires depuis longtemps mais qui nuiraient au framework d'origine.

Lorsque j'ai proposé des interfaces en retour, je ne pensais pas à apporter les interfaces 1.1 d'origine, mais des interfaces mises à jour avec le nouveau design. Il pourrait y en avoir encore plus, comme l' a dit

Interfaces oui, support hérité si possible, mais ne devrait pas être une priorité à ce stade.

Réouverture car il y a beaucoup d'intérêt pour ce sujet.

Il n'y a rien à rompre ici, il s'agit d'un nouveau framework et de l'occasion idéale de rompre les liens avec le code hérité et d'appliquer des modifications qui sont nécessaires depuis longtemps mais qui nuiraient au framework d'origine.

Alors, l'occasion idéale de se débarrasser des interfaces originales mal conçues et de se standardiser sur des classes de base comme ADO.NET se fait déjà ? :visage de troll:

Sérieusement, vous avez le choix entre une API propre ou une compatibilité descendante. Choisissez-en un. Je ne vois pas comment avoir ton gâteau et le manger aussi.

@JamesNK mais c'est exactement le but. La rétrocompatibilité n'est pas requise, point final.

Vous plaisantez, mais les API mal conçues avec des interfaces étaient mauvaises parce qu'elles étaient mal conçues, pas parce qu'il s'agissait d'interfaces. =) Ce n'est pas comme si les interfaces ne sont pas utilisées absolument partout dans NET ou c'est quelque chose de nouveau. Concevez simplement la chose correctement cette fois et passez à autre chose.

ADO.NET est l'un des morceaux de code les plus stables de tout .NET. Il a connu deux ou trois changements importants en 15 ans. C'est l'API parfaite pour se stabiliser en une interface et la rendre plus simple pour tout le monde.

À noter, ce sujet ici est également l'un des problèmes les plus commentés, et a eu la même longue discussion sur les interfaces par rapport aux méthodes virtuelles, à la testabilité et autres.

@nvivo Je dois admettre que je suis confus. Après avoir établi que les classes de base permettaient la testabilité, ce thread s'est transformé en ramenant les interfaces pour permettre le portage du code .NET Framework vers .NET Core. Comment la refonte des interfaces et l'introduction de quelque chose de nouveau y contribuent-elles ?

Pourquoi ne pouvons-nous pas avoir d'interfaces originales pour la compatibilité descendante et aller de l'avant avec tout ce que vous choisissez (soit des classes abstraites, soit de petites interfaces) ? Les interfaces d'origine pourraient s'asseoir au-dessus de la nouvelle pile et fournir la rétrocompatibilité. Cette partie peut également être facultative.
Cela rendrait le portage facile tout en permettant une nouvelle voie.

@davkean

Je ne peux pas répondre à tous ceux qui ont commenté ici. J'ai proposé d'utiliser des interfaces comme API d'ADO.NET, mises à jour vers la nouvelle API actuelle. Je n'ai pas demandé d'apporter les interfaces d'origine et tous les problèmes qu'il avait. Le but était d'avoir une API définie plus propre et de faciliter la simulation et le test du code qui en dépend, principalement des bibliothèques d'abstraction de données et non du code utilisateur.

Les interfaces décrivent mieux les API comme @ploeh l'a judicieusement dit, et beaucoup plus faciles à se moquer. La conception actuelle est terrible pour se moquer et vous oblige à implémenter la quasi-totalité du fournisseur en tant que bibliothèque pour effectuer des tests simples. Si ce n'est pas important pour tout le monde, je peux comprendre. Mais je ne suis certainement pas d'accord pour dire que c'est assez testable aujourd'hui. Tester si une méthode A a été appelée avec le paramètre X en vérifiant si la méthode B appelée C avec les paramètres X, Y, Z n'est pas idéale.

Maintenant, juste pour voir comment les classes créent déjà un mauvais design :

  • Pourquoi DbCommand a-t-il une propriété DesignTimeVisible ? La prise en charge au moment de la conception est-elle une exigence pour qu'une connexion soit définie comme une connexion ?
  • Pourquoi y a-t-il un événement pour notifier les changements d'état mais pas pour notifier d'autres choses comme les commandes exécutées ou les transactions démarrées ? La notification est-elle même une exigence pour l'existence de connexions ou quelque chose qui facilite la création d'interfaces utilisateur ?
  • Un ConnectionStringBuilder est-il une exigence pour qu'un fournisseur existe ? Ou plutôt une bonne chose pour que les assistants VS fonctionnent immédiatement ?
  • Pourquoi DbDataReader définit des méthodes Get pour certains types de base mais n'en ajoute pas pour d'autres comme GetByteArray() et GetDateTimeOffset() ? Et la récupération d'un TextReader est GetSql* dans SqlDataReader) ?

Ce sont toutes des questions rhétoriques. Je suis sûr que tous ont des réponses convaincantes et que les choses ont été prises en compte. Le fait est que la conception actuelle n'est clairement pas quelque chose qui a été pensé comme une définition d'API , quelque chose qui recevrait probablement plus d'attention avec les interfaces.

Honnêtement, de l'extérieur, la discussion sur la conception semble s'être déroulée comme suit :

  • gardons ces événements ici car il est plus facile pour les assistants de Visual Studio de travailler immédiatement
  • supprimons les méthodes de récupération de schéma car nous avons EF et c'est ce que tout le monde devrait utiliser, point final.
  • gardons ces méthodes pratiques car elles sont prises en charge depuis .NET 1.1 et nous ne pouvons JAMAIS casser la compatibilité !
  • supprimons les tables de données et les ensembles de données et faisons en sorte que tout le monde venant de .NET 1.1 modifie l'intégralité de sa base de code de toute façon !
  • construisons un nouveau modèle de fournisseur axé sur le cloud computing, la communauté, l'open source et les applications de demain...
  • ... et construisons ce modèle sur la base des besoins d'hier en utilisant SqlClient comme cas de test _sole_ !
  • construisons un tout nouveau framework qui sera fourni avec chaque application, afin que personne n'ait à s'inquiéter des mises à jour qui cassent _plus jamais_ son application !
  • .. alors prenons la décision de ne pas ajouter d'interfaces car tout changement peut interrompre leurs mises à jour !

Oui, il y a un petit coup de gueule et cette discussion ne mène nulle part =)... Mais je voulais juste sortir ça de ma poitrine. On est en 2015, tout casse tout le temps et on s'y habitue. Il y aura 20 mises à jour d'ASP.NET MVC au cours des prochaines années, ce qui entraînera beaucoup plus de changements de rupture que les changements d'interface dans ADO.NET.

J'aime toujours .NET et ce que vous en faites en général, je suis sûr qu'il est urgent de sortir .NET Core v1 à temps et tout ne sera pas parfait. J'espère juste que la communauté pourra aider à orienter cela dans d'autres directions au fil du temps et que vous n'avez pas peur de casser les choses au fur et à mesure que nous avançons.

Pour les mainteneurs d'ORM, pourquoi ne pas

``` c#

si COREFX

espace de noms System.Data {
interface publique IDbConnection { ... }
}
```

et utilisez le modèle d'adaptateur pour envelopper le nouveau System.Data avec vos propres implémentations ? En fait, vous pouvez créer un package de code source ouvert pour celui-ci et le partager.

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

C'est le problème; plutôt qu'une approche réfléchie, nous obtenons une réécriture précipitée afin de respecter une échéance arbitraire.
Je préférerais qu'il soit tard, Q4/16 s'il le faut, plutôt que d'avoir de la nouvelle merde cassée. Nous sommes en 2015 et tout casse est une justification terrible.

@thefringeninja qui ajoute soit une dépendance complètement inutile et déroutante qui ne fonctionne qu'avec la moitié des systèmes (dans le cas partagé), soit conduit à des collisions de noms nécessitant extern alias à désélectionner (et beaucoup de confusion pourquoi la méthode qui prend un System.Data.IDbConnection n'acceptera pas les System.Data.IDbConnection différents mais identiques que vous lui proposez). En gros, cela rendrait les choses 10 fois pires.

Pouvez-vous donner un exemple concret @mgravell ? Je peux voir comment cela se briserait si vous utilisiez Type.GetType("System.Data.IDbConnection, System.Data") , ou peut-être dans des scénarios PCL.

Si orm A définit System.Data.IDbConnection, et orm B définit
System.Data.IDbConnection, alors il y a maintenant deux complètement différents et
interfaces incompatibles qui ont le même nom/espace de noms, conflit et
ne fonctionnent pas réellement à partir d'un des fournisseurs de base de données. ça ne résout rien,
essentiellement. Pire : il loue à des API inutilisables où quelqu'un s'attend à passer
dans un SqlConnection ou NgpSqlConnection - et cela ne fonctionne pas.

En fait, vous pouvez créer un package de code source ouvert pour celui-ci et le partager.

S'il ne s'agit pas de System.Data.Common, cela signifie que DbConnection ne l'implémente pas, et : autant ne pas vous en soucier.

Vous n'obtiendrez jamais un consensus pour que chaque mainteneur de fournisseur ORM ou ADO .NET prenne en charge une dépendance externe tierce (cela garantit à peu près que SQL Server ne le fera pas) et 2 bibliothèques redéfinissant une interface BCL de base ne peuvent pas être utilisées ensemble. Pire encore pour les frameworks de haut niveau (comme ServiceStack) qui référencent les interfaces System.Data dans les bibliothèques principales (qu'il faudrait maintenant définir) ne pourront plus utiliser aucun ORM qui ne référence pas les mêmes interfaces - ce qui n'est pas le cas. -on voudrait ou devrait.

La seule façon de vous assurer que chaque bibliothèque référence les mêmes interfaces System.Data est de les restaurer avec les classes de base qui les implémentent - ce que je ne sais toujours pas quel mal cela a.

@mgravell ah dépendance transitive, n'avait pas envisagé cela. :+1:

Vous savez que je ne vois pas pourquoi c'est un problème à moins que vous ne coupiez étroitement votre code à un code que vous ne possédez pas. Protégez votre code de ses dépendances ! Enveloppez-le et abstrayez-le. Il existe de nombreuses façons de le faire et de rendre votre code testable. Beaucoup sont mentionnés ci-dessus. Vous testez l'intégration des bits que vous ne possédez pas. C'est ainsi que cela fonctionne. Vous ne devriez pas vous moquer des objets BCL ! Si vous l'êtes, votre conception n'est pas bonne.

@nvivo Je comprends qu'il s'agit de votre problème d'origine, mais sa direction s'est maintenant transformée en un fil de discussion sur le retour des interfaces de l'ère v1 pour des raisons de compatibilité. Gardons le cap sur cela - si vous souhaitez discuter des modifications à apporter à la surface actuelle, veuillez déposer de nouveaux problèmes.

@mythz Nous avons eu deux problèmes avec les interfaces ; 1) ils ont introduit une dépendance (lourde) sur DataSet, qui n'appartient pas aux abstractions sans politique et 2) ils apportent un ensemble parallèle d'abstractions aux classes de base mais sont verrouillés avec la surface v1. Nous voulions éviter cette confusion.

Je suis d'accord qu'il n'est pas viable pour un tiers de fournir ces interfaces - elles doivent être implémentées sur les abstractions de base pour être utiles.

Je comprends qu'il s'agit de votre problème d'origine, mais sa direction s'est maintenant transformée en un fil de discussion sur le retour des interfaces de l'ère v1 pour des raisons de compatibilité. Gardons le cap sur cela - si vous souhaitez discuter des modifications à apporter à la surface actuelle, veuillez déposer de nouveaux problèmes.

Cela n'a absolument aucun sens.

@nvivo cela signifie que vous n'êtes pas celui qui a le problème malgré l'avoir classé - évident en l'ayant fermé. Le problème consiste à restaurer les interfaces System.Data pour alléger le fardeau de la prise en charge de l'ensemble de l'écosystème qui en dépend. Tu as l'air d'être d'accord avec :

On est en 2015, tout casse tout le temps et on s'y habitue.

Mais ce n'est pas une stratégie satisfaisante pour ceux d'entre nous qui doivent prendre en charge les bases de code existantes et les bases de code de nos clients, et ne devrait certainement pas être la stratégie par défaut pour les dépositaires de bibliothèques BCL affectant l'ensemble de .NET.

Mais ce n'est pas une stratégie satisfaisante pour ceux d'entre nous qui doivent prendre en charge les bases de code existantes

@mythz Ceci est hors contexte. Ce n'est pas ce que je voulais dire. Tout le monde ici doit prendre en charge les bases de code existantes, je doute qu'il y ait un nouveau venu sur .NET dans la discussion.

Le problème avec ce qu'est devenu cette conversation, c'est qu'elle n'a pas beaucoup de sens. .NET Core est un nouveau framework, pas une mise à niveau. Une grande partie de l'API .NET complète existante n'est pas là et ne le sera pas. La compatibilité descendante ne fonctionnera pas comme ça de toute façon.

@nvivo Ce sentiment exact est la raison pour laquelle ce problème ne s'applique pas à vous. Si vous pensez que la rétrocompatibilité n'est pas importante, vous n'avez jamais essayé de prendre en charge une base de code significative ciblant plusieurs plates-formes - vous ne parlez pas non plus au nom de l'équipe CoreCLR. Ces bibliothèques n'ont pas été développées à partir de zéro, si vous lisez ci-dessus, vous constaterez que l'objectif principal des bibliothèques CoreCLR est de s'exécuter sur le .NET Framework complet. CoreCLR est une autre cible de plate-forme dont le portage des bibliothèques existantes est essentiel à son succès, ce que l'équipe .NET encourage activement et que ces interfaces manquantes entravent actuellement.

Avec toutes ces discussions sur le fait que les interfaces ne sont pas compatibles avec les versions, cela me fait penser à la façon dont le langage de programmation Go évite ce problème avec les interfaces implicites.

On m'a demandé de développer ce que j'entendais par abstractions _sans politique_.

Fondamentalement, par sans politique, j'entends que les abstractions System.Data.Common contiennent presque aucune règle métier - tout ce qu'elles font est de fournir une forme d'API qu'un fournisseur donné doit implémenter. Cela contraste avec DataSet, qui contient beaucoup de règles et de code métier. Les types sans stratégie, en raison de leur construction même, ont tendance à être versionnés moins fréquemment que les types qui contiennent une stratégie, car il y a moins de code, donc moins de bogues et de modifications de conception. Nous voulons des abstractions et des types qui sont _échangés_[1] entre des bibliothèques tierces en version rarement[2] pour réduire le nombre de problèmes que vous rencontrez lors de la coordination des dépendances sur un grand graphe de packages. Vous ne pouvez pas intégrer ou fusionner les types d'échange dans le cadre de votre application, alors que les types non-échange vous le pouvez. Par conséquent, pourquoi nous voulons qu'ils se séparent.

[1] Par _exchanged_, j'entends les types qui ont tendance à apparaître sur les API publiques. Par exemple, nous considérons Collection<T> un type d'échange, mais pas List<T> .
[2] L'utilisation du versioning sémantique pour ceux-ci provoquerait des ruptures presque identiques à celles ci-dessus avec les interfaces supprimées, car vous « fork » l'écosystème ; les bibliothèques doivent décider si elles doivent cibler la bibliothèque avant ou après la pause, ou se forger elles-mêmes pour gérer la scission.

@mythz Je dois prendre en charge les orms/clients dans le cadre d'une application commerciale et d'un code existant... Je ne dis pas que je suis d'accord avec les deux côtés, mais le fait est que dnx est un tout nouveau framework/runtime. S'il n'a pas d'interfaces, traitez-le... avec une directive de compilateur.

S'il n'a pas d'interfaces, traitez-le... avec une directive de compilateur.

Oh? qu'en est-il d'une méthode qui renvoie IDataReader ou d'une méthode qui accepte IDbConnection ? Ou IDbTransaction ? Comment allez-vous #ifdev autour de cela, si votre code _customers_ utilise cette API ?

'Traitement avec ça'... quel genre d'arrogance est-ce ?

Simple, mettez à jour le package sous-jacent (votre organisation) pour renvoyer votre propre type ou le type de base qu'ils prennent en charge depuis 2.0. Si vous ciblez les anciennes versions de .net, vous pouvez utiliser une directive pour renvoyer l'interface à la place et la marquer comme obsolète.

Oui, ça craint, mais je suis sûr qu'ils (des individus vraiment intelligents qui y pensent tout le temps) l'ont fait pour une bonne raison à l'époque (de retour dans .net 2.0). Une conversation peut-elle avoir lieu et peut-être que cela changera bien sûr. Mais le fait est que les personnes qui mettent à niveau vers le nouveau runtime devront faire un peu de travail. Il ne s'agit pas de cliquer sur un bouton dans une interface utilisateur sophistiquée et d'avoir du travail à faire pour eux. Mais en même temps, je suis d'accord avec vous pour dire que la mise à niveau vers le nouveau framework devrait être plus facile que de remplacer un tas de types.

@FransBouma , c'est probablement quelqu'un qui préconise aussi un nom fort.

@FransBouma @phillip-haydon peut emmener votre trolling ailleurs, vous ne pouvez pas vous attendre à agir comme ça et les gens vous prennent au sérieux. Jetez un œil à mes contributions open source / projets impliqués si vous avez des doutes... Je vais devoir gérer ça... de toute façon...

Pour mémoire, je suis contre les noms forts.

Faites avec...

Et tu dis que je trolle ?

" @FransBouma , c'est probablement quelqu'un qui préconise aussi un nom fort." est hors sujet, et pas très utile à cette discussion. Oui, c'est comme si tu trollais..

Un fait important à considérer dans cette discussion est que les interfaces IDb* ont été dépréciées en tant qu'API pour ADO.NET dans .NET 2.0 il y a une décennie, lorsque les classes de base ont été introduites. Ils n'ont pas été marqués comme obsolètes, mais tout ce qui a été construit depuis cette époque dépend plutôt des classes de base. Les fournisseurs App.config et la prise en charge des chaînes de connexion viennent à l'esprit.

Si vous avez du code dépendant de ces interfaces, vous codez contre une API très obsolète sans prise en charge de choses comme les méthodes asynchrones, ce qui signifie que vous devrez quand même la mettre à jour si vous voulez que les gens continuent à l'utiliser.

Simple, mettez à jour le package sous-jacent (votre organisation) pour renvoyer votre propre type ou le type de base qu'ils prennent en charge depuis 2.0. Si vous ciblez les anciennes versions de .net, vous pouvez utiliser une directive pour renvoyer l'interface à la place et la marquer comme obsolète.

C'est une API publique, utilisée par plusieurs milliers d'applications et l'API est publique et utilisée depuis .net 1.0. Ce n'est pas "simple", au contraire. Nous ne pouvons pas simplement changer l'API car Microsoft pense que c'est ce qu'ils doivent faire pour améliorer nos vies : ce sera un gros fardeau pour nos utilisateurs et donc pour nous.

Oui, ça craint, mais je suis sûr qu'ils (des individus vraiment intelligents qui y pensent tout le temps) l'ont fait pour une bonne raison à l'époque (de retour dans .net 2.0). Une conversation peut-elle avoir lieu et peut-être que cela changera bien sûr. Mais le fait est que les personnes qui mettent à niveau vers le nouveau runtime devront faire un peu de travail. Il ne s'agit pas de cliquer sur un bouton dans une interface utilisateur sophistiquée et d'avoir du travail à faire pour eux. Mais en même temps, je suis d'accord avec vous pour dire que la mise à niveau vers le nouveau framework devrait être plus facile que de remplacer un tas de types.

c'est la chose : ce n'est pas vu comme un « nouveau runtime ». Si c'était le cas, comme j'en ai déjà parlé, ce ne serait pas un problème. Cependant, Microsoft a l'idée que les dll de ciblage CoreFX doivent également fonctionner sur .NET complet, il n'y a donc pas de nouveau framework. Pour les mainteneurs de bibliothèques ciblant également .NET full, avec des fonctionnalités qui ne sont pas dans CoreFX (donc beaucoup de bibliothèques disponibles aujourd'hui) sont très "fun" car ils devront maintenir 2 versions. Pas 2 ou 3 #ifdevs et le problème est résolu, mais beaucoup d'entre eux. C'est peut-être différent pour vous car vous pouvez peut-être facturer à votre client les heures que vous devez consacrer au changement d'API. C'est différent lorsque vous créez un système à usage général qui est utilisé par beaucoup.

Si la prise en charge d'un framework compact est une ligne de conduite, la prise en charge d'un ORM sur .net complet et CoreCLR sera une perte de temps terrible, beaucoup de frustration et en fait pas vraiment beaucoup de gain : vous n'obtiendrez pas de nouvelles fonctionnalités, vous ne faites que contourner l'_absence_ d'entre elles .

(et avant que quelqu'un ne commence par : "mais ça tourne sous linux, tu vas gagner ça" : nos trucs tournent sur Mono depuis de nombreuses années. Donc non, ce n'est pas vraiment une nouvelle fonctionnalité à gagner, c'était déjà là).

SellMeThisFramework. Oh pourquoi je m'embête même.

mais tout ce qui a été construit depuis cette époque dépend des classes de base à la place

_toux_ Linq-to-SQL DataContext _toux_

Comme, en effet, beaucoup d'ORM non MS, d'où le problème. Pour pimpant, nous venons de mordre
la puce et migré vers DbConnection. Si nous avions encore le temps, je
suggérerait fortement à MS d'utiliser [Obsolete] lorsqu'ils rendent quelque chose obsolète. Mais:
nous ne pouvons pas changer le passé.

C'est un problème très pénible à résoudre, d'autant plus que la plupart
les auteurs de bibliothèques doivent continuer avec les deux API (compiler une façon pour
net40 etc, et une autre façon pour DNX). J'ai posté précédemment le sacré bordel
ce pimpant utilise pour faire ça : ce n'est pas joli, et ce n'est pas aussi simple que

si.

Le 27 novembre 2015 à 20h07, "Natan Vivo" [email protected] a écrit :

Un fait important à considérer dans cette discussion est que l'IDb*
les interfaces ont été dépréciées en tant qu'API pour ADO.NET dans .NET 2.0 il y a dix ans
lorsque les classes de base ont été introduites. Ils n'étaient pas marqués comme obsolètes, mais
tout ce qui a été construit depuis cette époque dépend plutôt des classes de base.
Les fournisseurs App.config et la prise en charge des chaînes de connexion viennent à l'esprit.

Si vous avez du code dépendant de ces interfaces, vous codez par rapport à un
API très obsolète sans prise en charge de choses comme les méthodes asynchrones, ce qui signifie
vous devrez quand même le mettre à jour si vous voulez que les gens continuent à l'utiliser.

-
Répondez directement à cet e-mail ou consultez-le sur GitHub
https://github.com/dotnet/corefx/issues/3480#issuecomment -160198453.

Je ne vois pas pourquoi les méthodes asynchrones ne peuvent pas être ajoutées à la suite de l'utilisation d'interfaces. Vous auriez pu créer de nouvelles interfaces pour les méthodes asynchrones. IAsyncDbCommand , IAsyncDataReader etc. Ensuite, vous pouvez faire en sorte que les classes de base implémentent les deux types d'interfaces.

Les utilisateurs d'ADO.NET utilisent soit la version asynchrone, soit les versions synchrones, pas les deux. Cela aurait donc fonctionné à merveille.

Pour les développeurs de bibliothèques, peu importe que la fonctionnalité augmente et que les interfaces restent les mêmes. N'est-ce pas le but ? Introduire de nouvelles interfaces pour de nouvelles fonctionnalités. Travailler avec des classes de base est juste pénible.

Puis-je simplement résumer le fil ici?

Plusieurs experts indépendants reconnus de la communauté sur les outils de données .NET,
y compris plusieurs auteurs et mainteneurs ORM vous disent - assez
clairement - que cela représente un ensemble important de problèmes. je ne pense pas
chacun d'entre nous est ignorant des subtilités, ou naïf de la programmation
principes, et la plupart d'entre nous, sinon tous, connaissent bien l'histoire,
parce que nous étions là à ce moment-là.

La réponse officielle semble être "ça nous semble bien, et EF est content".
Oui, nous le savons, car la décision a été prise en premier lieu.

Eh bien, nous avons tous exprimé nos opinions, même si cela n'a pas été fructueux.
Le 27 novembre 2015 à 20h41, "Jonas Gauffin" [email protected] a écrit :

Je ne vois pas pourquoi les méthodes asynchrones ne peuvent pas être ajoutées en tant que
résultat de l'utilisation d'interfaces. Vous auriez pu créer de _nouvelles_ interfaces pour
les méthodes asynchrones. IAsyncDbCommand, IAsyncDataReader etc. Ensuite, vous pouvez
faire en sorte que les classes de base implémentent les deux types d'interfaces.

Les utilisateurs d'ADO.NET utilisent soit la version asynchrone, soit la version synchrone
versions, pas les deux. Cela aurait donc fonctionné à merveille.

Pour les développeurs de bibliothèques, peu importe que les fonctionnalités évoluent et
les interfaces restent les mêmes. N'est-ce pas le but ? Présenter de nouveaux
interfaces pour de nouvelles fonctionnalités. Travailler avec des classes de base est juste pénible.

-
Répondez directement à cet e-mail ou consultez-le sur GitHub
https://github.com/dotnet/corefx/issues/3480#issuecomment -160201361.

Dudes.. mettez à jour votre code et modifiez votre version majeure. Terminé.

Oui, mais il n'y a aucune raison pour que vous ne puissiez pas remplir cette interface avec une directive du compilateur lors du ciblage du noyau. Je l'ai fait avec certains de nos packages pcl.

Je pense que Microsoft doit réitérer que le noyau n'est pas plein de points nets, mais cela n'aide toujours pas. Je pense que Microsoft doit nettoyer certaines interfaces pour être honnête. Il y a eu un article de blog récemment où il y a des interfaces très incohérentes et on ne sait jamais laquelle choisir. Je pense que définir une deuxième interface async est nul. Ce serait bien si tout était asynchrone..

Ce serait bien si le framework complet était passé en revue pour s'assurer que les choses qui doivent être marquées comme obsolètes sont... Et publiées en tant que 4.6.2

@mgravell +100. Bien dit, 100% d'accord.

Combien est vraiment touché? On parle de coreclr ici ? Le bureau .NET sera actif pendant de nombreuses années jusqu'à ce que coreclr puisse rattraper son retard. Exactement pour ceux qui se plaignent, quelle est votre perte de couverture ici ? Beaucoup de gens disent essentiellement que c'est la fin du monde.

@leppie En effet, il existera pendant de nombreuses années. Et nous devrons également maintenir ces hacks et solutions de contournement dans notre code pour les années à venir. Le point de discorde ici est la suppression du pont commun entre les deux. Cette charge de travail a été transférée à tous les développeurs de bibliothèques au lieu de la BCL. Je comprends les avantages et les inconvénients des deux côtés de l'interface, mais je ne comprends pas l'attitude "c'est mineur, passez à autre chose" de certains ici.

Soyons francs ici : si les consommateurs de bibliothèques doivent tous faire la même chose, cela devrait être dans la BCL . Le débat est « quelle forme cela prend-il ?

Du côté positif de la suppression des interfaces, il existe un mécanisme de gestion de version _supplémentaire_ avec le nouveau modèle d'emballage maintenant en jeu : les classes disponibles dans X, Y et Z sont désormais bien mieux prises en charge par l'outillage. Par exemple dotnet5.2 vs 5.4 actuellement. Mais il y a aussi des inconvénients. Par exemple, SqlClient n'est toujours pas au point d'implémenter les interfaces telles qu'elles sont aujourd'hui (voir dotnet/runtime#14302 et dotnet/runtime#15269), et compte tenu de ce que @YoungGah a dit (à moins que je ne me trompe), nous attendons sur 5.4 ou 5.5 pour ce même niveau de prise en charge du schéma, des insertions en bloc, etc.

Alors, que se passe-t-il avec 5,6 (1,5) ? Si plus de membres sont ajoutés aux classes abstraites, chaque fournisseur de données doit suivre le rythme de la cible mobile qui peut changer avec chaque personne en mouvement ? Chaque consommateur doit déterminer la version des fonctionnalités disponibles dans chacun d'eux ? Nous devons compiler une version de l'assembly pour chaque version de la plate-forme à l'avenir pour correspondre à la base abstraite de la classe transmise ? Comment tout cela fonctionne à l'avenir avec les ajouts n'est pas clair à 100%. Une interface qui ne change pas est beaucoup plus claire. En plus de cela, il y a la documentation : quelles fonctionnalités, méthodes, etc. sont disponibles dans quelles versions _et plates-formes_ vont être un énorme problème pour tous les auteurs de bibliothèques à l'avenir. Cette préoccupation n'est que semi-liée ici, mais elle est en jeu.

Pour l'instant, j'attends avec impatience la mise à jour dans les 2 prochaines semaines. Ma crainte est que ce soit effectivement le cas, comme le message tout le temps a été : "Nous faisons X parce que cela fonctionne pour SQL et Entity Framework, et c'est assez bon" - sans utiliser aucun de ces mots. La frustration du côté de l'auteur de la bibliothèque, pour moi, a été un manque de progrès (à la fois dans le code et dans la discussion) sur ces fronts depuis des mois maintenant.

100% d'accord.

Lorsque j'ai conçu la v2 (et plus) de SqlFu (mon Micro ORM), j'ai dû décider où attacher les méthodes d'extension : à DbConnection/DbCommand ou aux interfaces. J'ai trouvé ça et j'ai décidé d'opter pour les cours abstraits.

Par conséquent, je ne suis pas QUE affecté, bien que je sois affecté par la suppression de IDataReader , car MS, dans sa sagesse, a décidé de ne pas indiquer très clairement quelles interfaces devraient être traitées comme obsolètes et lesquelles ne devraient pas l'être. Mais dans mon cas, il n'est pas difficile de remplacer l'interface.

Cependant, je vois l'intérêt d'avoir des interfaces dédiées et je ne pense pas qu'il soit si difficile pour MS de les conserver/rajouter. S'ils décident que les anciennes interfaces ne sont pas si bien conçues, tant mieux ! Concevez les nouveaux pour être plus spécifiques. Au moins à l'avenir, nous n'aurons pas à faire face au même problème.

(C'est la semaine de Thanksgiving aux États-Unis, donc les réponses des Microsofties seront assez limitées jusqu'à ce qu'ils reviennent au bureau la semaine prochaine)

Je veux juste réitérer - afin de ne pas perdre de bonnes suggestions/bogues dans ce fil, si vous avez des problèmes avec les classes de base/surface actuelles, et/ou la façon dont ils version à l'avenir, veuillez déposer un nouveau problème, gardons cette discussion uniquement sur les interfaces v1.

@NickCraver Similaire à la compatibilité de version à version de .NET Framework, il n'y aura pas de modifications importantes entre les versions de la surface .NET Core. Par exemple, l'ajout de membres abstraits aux classes de base serait un exemple de changement qui _ne sera pas_ effectué.

@davkean à quel point êtes-vous sûr que cela n'arrivera pas ? Étant donné que nous voyons une surface incomplète et qu'il n'y a aucune garantie que cela change, il est difficile de croire que les pièces manquantes n'apparaîtront pas plus tard, voire pas du tout. Cependant, je pense qu'aucun changement de rupture n'est une chose _plus_ importante, ce que la plupart des auteurs de bibliothèques supposeraient également ici. Cela signifie qu'il est encore plus critique que ces éléments soient pris en charge bien avant l'arrivée du RTM.

Pour mémoire, il existe des problèmes distincts classés sur la surface, voir dotnet/runtime#14302 et dotnet/runtime#15269 avec les dernières mises à jour de Microsoft les 25 septembre et 2 octobre respectivement - malgré les demandes de mises à jour et d'activité plusieurs fois par la suite. Cela fait 2 mois et 2 sorties qui se sont écoulées, avec silence. Ceci malgré le fait que dotnet/runtime#14302 soit le problème le plus actif dans ce référentiel (et celui-ci vient de devenir le 2ème). Comprenez-vous notre frustration ?

Je suis absolument convaincu que nous n'apporterons pas de changements de rupture, l'équipe Data Common cherche à les faire sans introduire de membres abstraits.

@NickCraver Désolé, nous allons mal ici - ces problèmes n'ont pas été oubliés, @YoungGah a fourni une mise à jour ci-dessus à leur sujet, je m'assurerai qu'elle mette à jour les problèmes avec les progrès. Beaucoup de MS s'habituent encore à ce _travail à l'air libre_, cela s'améliorera avec le temps - merci de nous avoir appelé à ce sujet.

@niemyjski

dnx est un tout nouveau framework/runtime

Si vous pensez que les bibliothèques dnx runtime et corefx se sont manifestées à partir de rien, vous sous-estimez sérieusement le temps qu'il faudrait pour les développer à partir de zéro. Le fait que les bibliothèques CoreFx s'exécutent sur le .NET Framework complet devrait vous donner un indice que, non, ce n'est pas complètement nouveau.

S'il n'a pas d'interfaces, traitez-le... avec une directive de compilateur.

Oui, mais il n'y a aucune raison pour que vous ne puissiez pas remplir cette interface avec une directive du compilateur lors du ciblage du noyau.

Si vous avez pris la peine de lire les commentaires avant de vous lancer dans ce fil, vous saurez que a) il y a des raisons et b) il s'agit d'une stratégie brisée et irréalisable pour les interfaces BCL de base.

@nvivo

Un fait important à considérer dans cette discussion est que les interfaces IDb* ont été dépréciées en tant qu'API pour ADO.NET dans .NET 2.0 il y a une décennie, lorsque les classes de base ont été introduites.

Si tel était le cas, vous n'auriez pas ouvert un problème en leur disant de revenir à l'utilisation d'interfaces dont vous saviez sciemment qu'elles étaient dépréciées par les classes de base il y a dix ans. La façon dont vous communiquez une API est dépréciée consiste à utiliser l'attribut [Obsolete] qui est son seul but pour exister. Si ce n'est pas largement communiqué, ce n'est pas obsolète, quelles que soient vos pensées maintenant. Le fait que la plupart des ORM non MS .NET en dépendent devrait indiquer que sa dépréciation a été mal communiquée, voire pas du tout.

Si vous avez du code dépendant de ces interfaces, vous codez contre une API très obsolète sans prise en charge de choses comme les méthodes asynchrones, ce qui signifie que vous devrez quand même la mettre à jour si vous voulez que les gens continuent à l'utiliser.

Un faux bonhomme de paille - l'un n'implique pas l'autre. Nous avons déjà ajouté la prise en charge des API asynchrones, et non, leur ajout n'a pas brisé les bases de code client existantes et aucune des API existantes n'a eu besoin de changer.

D'accord, c'est bien de prendre un bon départ, mais puis-je poser une question : quels compromis ont été faits pour prendre en charge vos propres frameworks ? Quelles horreurs du passé ont été migrées parce qu'elles sont nécessaires pour faire fonctionner, disons, Entity Framework ?

Il serait dommage de faire disparaître les MicroORM, ils rendent le code .Net quelque peu performant (EF est une bête inutilisable pour les applications où 500ms pour charger quelques lignes n'est pas acceptable).

En ce qui concerne les interfaces vs les classes de base : les classes de base sont excellentes tant que tout ce qui peut être réutilisé est virtuel. Par exemple, l'une des décisions de conception les plus irritantes dans WCF est l'utilisation abondante de classes scellées qui contiennent de nombreuses fonctionnalités. Supposons que vous deviez apporter un petit ajustement à la façon dont les messages XML sont gérés (parce que : interop). Au lieu d'hériter et de remplacer une petite fonction, vous devez la ré-implémenter. Dans l'exemple WCF, le S dans SOLID a été ignoré, de sorte qu'il vous reste généralement à implémenter une grande interface sans aucun des tests requis pour garantir sa qualité de production.

Donc : les classes de base que nous pouvons adapter sont une bonne chose.

Je suis absolument convaincu que nous n'apporterons pas de changements de rupture, l'équipe Data Common cherche à les faire sans introduire de membres abstraits.

@davkean C'est impossible à garantir, et vous le savez. ADO.NET est un sous-système pour communiquer avec des logiciels tiers avec une grande variété de fonctionnalités, qui sont exposées via une API commune avec quelques points d'extension. Les choses changent, même dans le domaine des bases de données, et ces changements se répercutent sur l'API utilisée pour communiquer et utiliser ces services de base de données externes. En outre : les changements de comportement _est_ également un changement décisif. Et nous les avons vus aussi dans ADO.NET (par exemple à propos de la gestion des erreurs) au cours des dernières années.

L'ensemble de l'API ADO.NET regorge des effets secondaires de ces changements, souvent entraînés par SQL Server ; cela n'a guère été le cas que les choses aient été conçues en général puis déplacées vers SQL Client, mais l'inverse (il n'y a par exemple pas beaucoup de fonctionnalités, voire aucune, dans les classes de base qui sont ignorées par SqlClient). De plus, les éléments nécessaires aux tiers n'ont jamais été intégrés à l'API.

Donc, en bref, c'est une API qui, au début avec .NET 1.0 avait une conception générale (qui s'est avérée gravement imparfaite dans de nombreux domaines) et qui depuis lors a été rafistolé avec des fonctionnalités à gauche et à droite pour faire face aux changements de le paysage. _La plupart_ d'entre eux sont toujours dans l'API (sinon tous). Et maintenant, Microsoft en supprimera une : les interfaces.

Il n'y a absolument rien à gagner en supprimant un élément aléatoire de l'API : aucune fonctionnalité n'est ajoutée via cela (vous pouvez passer du temps là-dessus au lieu de repousser ici par exemple), mais le code qui s'appuie sur cet élément de l'API ne fonctionnera pas. Si le but derrière tout ce déplacement de fromage est de « recommencer », alors faites-le, mais faites-le en repensant l'API pour en faire une véritable API à usage général, débarrassez-vous de _toutes_ les croquettes qui se sont accumulées au fil des ans .

Mais ce n'est pas fait. Personne n'a à se demander pourquoi, nous savons tous pourquoi. Nous savons également que si une équipe au sein de MS avait été gravement touchée par la suppression des interfaces, elle n'aurait jamais été supprimée en premier lieu.

Si Microsoft peut ajouter de nouvelles fonctionnalités via des classes de base afin que les fournisseurs tiers implémentent automatiquement «une forme de» la fonctionnalité (comme avec Async, où la méthode async revient à la méthode de synchronisation si le fournisseur ne l'implémente pas), super : que signifie que nous, les développeurs ORM tiers (et faites-vous face : de nombreux développeurs accèdent à _votre_ API via le code de (micro)ORM tiers) peuvent simplement cibler une classe et c'est tout.

Mais il n'est pas garanti que vous le feriez. Par exemple, personne au sein de Microsoft ne s'est jamais soucié des fonctionnalités spécifiques pour Oracle ou PostgreSql à ajouter à ADO.NET. Par exemple, l'utilisation d'UDT, les arborescences de documents, plusieurs ensembles de résultats via des curseurs, chaque fournisseur ADO.NET doit trouver sa propre façon de gérer ces fonctionnalités. Que se passe-t-il si (quand ?) SQL Server obtient une fonctionnalité d'arborescence de documents, par exemple avec des documents JSON, ADO.NET sera-t-il mis à jour avec une nouvelle API pour cela ? Comme vous l'avez fait par le passé avec les rapports d'erreurs des fournisseurs ADO.NET ?

Vous ne pouvez pas faire de telles garanties, et il est imprudent d'affirmer ici que MS ne cassera rien à l'avenir. Ils l'ont toujours fait et parfois ils ont même dû le faire : après tout, chaque API a des défauts, et ADO.NET en regorge ; d'une manière ou d'une autre, un jour, quelqu'un les "réparera".

Donc, pour récapituler : les interfaces font partie d'ADO.NET, tout comme les parties bâclées ailleurs dans l'API font partie d'ADO.NET. Ceux-ci ne sont pas supprimés pour corriger l'API, ni l'API remaniée pour en faire une API à usage plus général : elle a été laissée telle quelle, avec certains éléments supprimés comme les éléments dépendant de DataSet/Table car ceux-ci ne sont pas portés (et il sont d'autres problèmes qui en débattent avec des progrès similaires), sauf que... les interfaces sont supprimées.

De ce seul point de vue, cela n'a déjà aucun sens.

@mythz

Si tel était le cas, vous n'auriez pas ouvert un problème en leur disant de revenir à l'utilisation d'interfaces dont vous saviez sciemment qu'elles étaient obsolètes

Vous ne pouvez pas lire l'OP et comprendre cela. Ces discussions deviennent trop religieuses et vous supposez simplement des choses que personne n'a dites.

J'ai ouvert ce problème parce que je pense que les interfaces décrivent mieux une API et aident à tester. Si c'est fait, je ne pense pas qu'ils devraient être compatibles avec une API de 15 ans qui avait ses problèmes. La rétrocompatibilité n'a jamais été un point dans le problème jusqu'à ce que vous déplaciez la discussion à cela.

Ce n'est pas que je crois que les choses devraient se casser juste pour le plaisir. Mais la gestion des versions d'interface est un problème du passé. Si corefx change quelque chose entre les versions majeures, ses versions majeures devraient avoir des changements de rupture. S'ils cassent une interface entre des versions mineures, c'est juste de la négligence.

Nous avons déjà ajouté la prise en charge des API asynchrones

Vous ne pouvez pas ajouter une API asynchrone au-dessus d'une API de synchronisation. Si vous l'avez fait en utilisant IDbConnection ou IDbCommand, vous l'avez mal fait. Si vous n'utilisez pas ces interfaces, vous n'avez aucun intérêt à défendre une compatibilité descendante avec elles.

Nous avons déjà ajouté la prise en charge des API asynchrones

Vous ne pouvez pas ajouter une API asynchrone au-dessus d'une API de synchronisation. Si vous l'avez fait en utilisant IDbConnection ou IDbCommand, vous l'avez mal fait. Si vous n'utilisez pas ces interfaces, vous n'avez aucun intérêt à défendre une compatibilité descendante avec elles.

Dans ADO.NET, c'est ce qu'ils ont fait : les méthodes Async reviennent par défaut aux variantes de synchronisation. De cette façon, tous les fournisseurs ADO.NET qui ne prennent pas en charge Async (lire : tous sauf SqlServer pour le moment) n'ont pas à implémenter des choses qu'ils ne prennent pas en charge : le code tiers dans les ORM offrant une API Async peut programmer contre les méthodes Async dans ADO.NET et si le fournisseur ado.net ne prend pas en charge l'async, personne ne le saura réellement. Bon... vous le saurez parce que c'est plus lent, mais ça mis à part.

Maintenant, c'est aussi une bonne illustration de l'absence de tout 'design' ou architecture générale au sein d'ADO.NET : il n'y a _aucun_ moyen de créer un point de sauvegarde transactionnel dans l'API générale. Bien que presque toutes les bases de données prennent en charge cela avec une méthode 'Save(string)' sur leur classe dérivée de DbTransaction. Tous sauf OleDbTransaction (comme MS Access ne le prend pas en charge, du moins c'est mon soupçon).

Ce n'est pas facile, mais personne n'a dit que c'était facile. Ce problème n'est pas nouveau, OleDB et ODBC le traitent depuis de nombreuses années, JDBC a trouvé un moyen de le résoudre, Microsoft n'a pas à réinventer la roue pour surmonter ce genre de problèmes. Ce n'est pas non plus unique au domaine DB : par exemple, chaque carte vidéo prend en charge un sous-ensemble différent de fonctionnalités via son API, exposée au développeur via Direct3D/X. Il est en fait intéressant de voir comment se déroulent les conceptions dans ces autres mondes : l'API est conçue et les parties qui doivent la prendre en charge (pilotes JDBC, auteurs de pilotes OleDB, etc.) doivent les implémenter. Votre pilote ne supporte pas X ? Votre pilote n'est pas compatible avec X. "Oracle ne prend pas en charge ADO.NET v10". Personne au sein d'Oracle ne veut lire cela. Au lieu de cela, SqlClient est le leader, et ce qui tombe du wagon est ajouté à ADO.NET et c'est tout.

Dans ADO.NET, c'est ce qu'ils ont fait : les méthodes Async reviennent par défaut aux variantes de synchronisation.

Non, ce n'est pas le cas. L'API expose des méthodes asynchrones qui se replient sur les méthodes de synchronisation par défaut, mais les fournisseurs remplacent les opérations asynchrones réelles. Ce que @mythz déclare, c'est qu'il utilise IDbCommand et IDbConnection et qu'il le fait.

Ce n'est pas possible, point final. Si vous le faites, soit vous ne le faites pas correctement, soit vous n'utilisez pas l'interface. Vous ne pouvez pas inventer async si l'API sous-jacente n'est pas async.

Non, ce n'est pas le cas. L'API expose des méthodes asynchrones qui se replient sur les méthodes de synchronisation par défaut, mais les fournisseurs remplacent les opérations asynchrones réelles. Ce que @mythz déclare, c'est qu'il utilise IDbCommand et IDbConnection et qu'il le fait.

Aucun fournisseur officiel ne le fait à l'exception de SqlClient, tous les autres, par exemple ODP.NET, n'implémentent aucune forme de code asynchrone et, par conséquent, l'appel de code revient aux variantes de synchronisation (les méthodes async dans DbDataReader/DbCommand, etc. qui exécutent réellement le code de synchronisation ). le code utilisateur appelle donc une variante asynchrone, qui est sous le capot en train d'effectuer des opérations de synchronisation. Ce qui n'entraîne aucune asynchrone dans la pratique (car tout le code est simplement synchronisé dans la pratique). Peut-être que les fournisseurs de devart implémentent une API asynchrone dans leur propre implémentation, pas sûr.

Quoi qu'il en soit, il ne s'agit pas de faire les choses correctement, il s'agit de versionner les API.

@nvivo

J'ai ouvert ce problème parce que je pense que les interfaces décrivent mieux une API et aident à tester. Si c'est fait, je ne pense pas qu'ils devraient être compatibles avec une API de 15 ans qui avait ses problèmes. La rétrocompatibilité n'a jamais été un point dans le problème jusqu'à ce que vous déplaciez la discussion à cela.

Ok, vous saviez donc que les interfaces ADO.NET de base étaient obsolètes il y a 10 ans, avec tout déplacé vers les classes de base, mais vous pensiez qu'elles devraient simplement abandonner cela maintenant et revenir aux interfaces, en utilisant par coïncidence les mêmes noms que les interfaces existantes, mais le les interfaces existantes ne devraient plus exister, car la compatibilité descendante n'est pas requise, n'est-ce pas ? bien sûr, cela semble légitime.

Si vous voulez faire avancer une plate-forme, vous faites évoluer les API au fil du temps et les prenez en charge en parallèle, donnant à chacun la possibilité de prendre également en charge les API parallèles et de leur permettre de planifier leur chemin et leurs clients. Les arracher sans avertissement brise inutilement l'écosystème qui en dépend et repousse la complexité jusqu'à chaque dépendance en aval.

Vous ne pouvez pas ajouter une API asynchrone au-dessus d'une API de synchronisation. Si vous l'avez fait en utilisant IDbConnection ou IDbCommand, vous l'avez mal fait. Si vous n'utilisez pas ces interfaces, vous n'avez aucun intérêt à défendre une compatibilité descendante avec elles.

J'aimerais que vous arrêtiez de polluer ce fil avec des commentaires sur des choses dont vous n'avez clairement aucune connaissance. Lisez le code source si vous voulez savoir comment les API Async sont implémentées - et arrêtez de répandre aveuglément des mensonges. Il est impossible pour une bibliothèque tierce d'étendre les interfaces System.Data. Nous fournissons une API indépendante de l'implémentation qui, afin de prendre en charge tous les principaux SGBDR, expose la dépendance minimale que chaque fournisseur ADO.NET implémente dans son API externe, à savoir les interfaces System.Data de base. Les API asynchrones sont des méthodes d'extension d'IDbConnection qui exploitent en coulisses les API asynchrones sur les fournisseurs ADO.NET concrets qui les prennent en charge. En interne, il existe déjà des dépendances concrètes sur chaque fournisseur ADO.NET pris en charge, indépendamment de la prise en charge asynchrone. Votre suggestion selon laquelle nous "n'avons en fait aucun intérêt à défendre une compatibilité descendante avec eux" est inexpérimentée et totalement sans fondement.

Permettez-moi de poser cette question au côté Microsoft de la clôture (cc @davkean @YoungGah): Disons que c'est un monde parfait et que rien ne s'est jamais produit. Quand _faire_ tu veux casser des choses ? Des versions majeures comme la 6.0 ? Une autre fois? L'argument contre les interfaces est qu'elles ne sont pas versionnées. Eh bien oui, c'est valable - mais _si nous ne changeons pas non plus les classes abstraites_, c'est aussi un point discutable. Alors... pouvons-nous y voir clair ?

Suivis :
Si la réponse est oui (à un moment donné après RTM, il y aura des changements), alors quel genre de pause verrions-nous ? Ajouts, nouvelles méthodes? Si j'hérite de la classe de base de mon fournisseur, que se passe-t-il lorsque vous ajoutez une méthode conflictuelle que les gens utilisent, etc. ?

Si la réponse est non (jamais) : pourquoi ne pas simplement rajouter les interfaces ?

Ce fil est un peu bloqué sur la discussion _en ce moment_ - ce qui est surtout une bonne chose car ce problème doit être corrigé dès que possible. Chaque auteur de bibliothèque ici sait à quel point il est difficile d'obtenir quelque chose après une sortie, et c'est pourquoi nous insistons autant. Malheureusement, l'absence d'un plan clair pour les _futurs_ ajouts et modifications, le cas échéant, rend l'argument plus sous-informé.

Quels sont les projets pour l'avenir ?

Nous ne devrions pas forcer l'implémentation via des classes abstraites dans ce cas. OMI

Microsoft n'apportera pas de modifications non conformes pour .NET 4.5. Cela fait partie de Windows. La compatibilité est reine.

Microsoft pourrait apporter des modifications dans .NET Core qui n'ont pas d'impact sur la version 4.5. Je doute qu'ils publient 1.0 RTM sur quelque chose de bas niveau comme ADO.NET, mais la barre est plus basse. Cela ne fait pas partie de Windows et les versions .NET Core peuvent être déployées côte à côte.

Les classes abstraites peuvent être modifiées - ce n'est pas une rupture. Ajoutez simplement une méthode virtuelle avec une implémentation par défaut. Cela a déjà été fait avec les méthodes asynchrones ADO.NET. Avec l'introduction de .NET Core, je pense que les modifications des classes partagées devraient être effectuées de concert avec les versions .NET 4.5 pour maintenir la compatibilité. Quelqu'un me corrige si c'est faux et ne s'applique qu'aux interfaces :grin:

@FransBouma

Aucun fournisseur officiel ne le fait à l'exception de SqlClient, tous les autres, par exemple ODP.NET, n'implémentent aucune forme de code asynchrone et, par conséquent, le code d'appel revient aux variantes de synchronisation.

Vous avez raison, mais ce n'est pas un problème avec l'API, et plus de paresse ou de manque de compréhension de la part des implémenteurs. Le connecteur MySql, par exemple, a réimplémenté toutes ses méthodes asynchrones en créant un TaskCompletionSource et en les complétant avec des méthodes de synchronisation, ce qui est ridicule. Ils pourraient simplement supprimer la moitié de leur base de code et conserver le même comportement.

Ne pas dire que les interfaces résoudraient cela, mais ne pas avoir de comportement par défaut pour l'async ferait au moins réfléchir certains d'entre eux. Le fait que 90% des personnes très techniques ne comprennent pas les opérations asynchrones n'aide pas non plus.

Les classes abstraites peuvent être modifiées - ce n'est pas une rupture. Ajoutez simplement une méthode virtuelle avec une implémentation par défaut. Cela a déjà été fait avec les méthodes asynchrones ADO.NET.

C'EST la rupture. C'est une rupture pour toutes les bibliothèques qui ont sous-classé cette implémentation sans savoir qu'elle a été ajoutée et les gens consomment alors cette réflexion. Oh, cette implémentation est maintenant prise en charge avec postgresql BAM ERROR wtf s'est produit ...

L'implémentation forcée d'une abstraction de base de données est erronée.

Peu importe si ses interfaces ou une classe de base. Il y aura des changements de rupture. Mais la mise en œuvre prédéfinie forcée est erronée.

Le polymorphisme ne fonctionne pas ainsi. Vous ne pouvez pas surcharger une méthode sans le savoir. Si votre référence est un DbConnection et que vous appelez QueryAsync, il n'appellera que cette méthode ou tout ce qui a été remplacé. Une méthode appelée QueryAsync qui existait déjà dans une sous-classe ne sera pas appelée.

Vous confondez remplacer une méthode et la cacher avec le même nom.

@JamesNK

Si les méthodes sont définies comme abstraites, aucune implémentation n'existe dans la classe de base. Cela rompt le contrat pour les tiers car cela les oblige à ajouter une implémentation dans la sous-classe.

Si vous rendez la méthode virtuelle pour qu'elle puisse être remplacée, alors l'implémentation existe dans la classe de base qui pourrait n'avoir aucun sens pour la sous-classe. Cela ne fonctionne toujours pas car il existe une implémentation qui n'a pas été implémentée par l'auteur de la bibliothèque. Bien sûr, votre application peut compiler et tout va bien, mais quelqu'un appelle cette méthode et elle n'est pas valide pour la sous-classe. C'est faux. C'est une implémentation forcée qui n'appartient pas à la sous-classe.

Donc, classe abstraite où l'implémentation peut exister qui n'appartient pas à la sous-classe. Ou des interfaces où aucune implémentation par défaut n'existe pour les tiers.

@phillip-haydon c'est pourquoi il est implémenté en tant que méthode virtuelle, pas en tant que méthode abstraite.

Vous pouvez ajouter des éléments, cela ne brisera que les sous-classes qui ont déjà un membre avec la même signature (nom/arguments). Si les arguments sont différents, cela pourrait introduire des bogues subtils si les développeurs se trompent sur les surcharges.

C'est une implémentation forcée qui n'appartient pas à la sous-classe.

Alors ne le mettez pas là.

@jamesnk

Ne le mettez pas là. C'est pourquoi nous plaidons pour la suppression des interfaces.

Le rendre virtuel ne résout pas le problème. Il ne devrait pas y avoir de mise en œuvre prédéfinie. Fin de l'histoire

@JamesNK Dans ce cas, nous ne l'avons pas mis là, _Microsoft_ l'y a mis en l'incluant dans le résumé. L'ajout de méthodes censées fonctionner sur _tous_ les fournisseurs héritant jamais, je ne vois pas vraiment se dérouler efficacement, même s'il n'y a pas de rupture technique (je concède "devrait utiliser de nouveaux" avertissements de compilation _techniquement_ ne cassent pas). Il n'y aura tout simplement pas d'implémentation partagée ou immédiatement partagée dans _la plupart_ des cas. Alors, quelle est l'alternative ? throw new NotImplementedException() dans ce virtuel ? Ce n'est guère un argument pour qu'il existe en premier lieu, il est en proie à plus de problèmes (d'exécution).

Regardons aujourd'hui : je préférerais de loin voir un IDbAsyncConnection ajouté lorsqu'un fournisseur le prend en charge plutôt qu'un tas de méthodes synchrones sous les couvertures menant à la confusion et à l'inefficacité, ce que nous avons aujourd'hui sur ces résumés.

Je préférerais de loin voir un IDbAsyncConnection ajouté lorsqu'un fournisseur le prend en charge plutôt qu'un ensemble de méthodes synchrones sous les couvertures conduisant à la confusion et à l'inefficacité

@NickCraver +1000 à cela. Comme ce bogue ici où l'équipe Oracle ne comprend tout simplement pas ce que signifie async.

Vous pouvez le faire avec des interfaces. Le problème avec eux est que vous ne pouvez alors pas accepter les arguments qui exigent plusieurs interfaces, par exemple j'ai besoin d'un type qui est à la fois IDbAsyncConnection et IDbConnection. Vous perdez une frappe forte et vous devez commencer à rechercher des interfaces de style COM, ce qui, à mon avis, n'est pas très convivial. C'est un outil de conception d'API qui a sa place mais je ne sais pas si j'y irais par défaut.

Si l'implémentation par défaut lançait NotImplementedException, la boulonner sur la classe de base n'est pas la bonne chose à faire. Comme je l'ai dit, ne le mettez pas là alors. Si vous voyez quelqu'un le faire, soulevez un problème.

Quoi qu'il en soit, qu'il s'agisse d'interfaces ou de classes de base abstraites, mon expérience est d'ajouter de nouvelles fonctionnalités à une bibliothèque qui n'a pas été conçue à l'origine pour eux sans briser le monde est très difficile.

@JamesNK vraisemblablement IDbAsyncConnection hériterait de IDbConnection ici, mais ce n'est pas nécessairement le cas - ils pourraient partager des membres communs ou hériter d'une base commune. Par exemple, dans Dapper, nous implémenterions probablement comme suit :

``` C#
IEnumerableMettre en doute(ce cnn IDbConnection, cmd CommandDefinition)

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

J'imagine que la plupart des bibliothèques avec des méthodes sync/async auraient des utilisations et des implémentations similaires.

_Edit :_ après avoir tapé cela, je me rends compte à quel point Async à la fin du nom serait bien meilleur

ADO.NET a subi les changements majeurs suivants au fil des ans :

  1. En 2003 (1.1), ils ont apporté un changement radical par rapport à 1.0 et l'ont repensé
  2. En 2005 (2.0), ils sont passés au modèle de fournisseur avec les classes de base qui existent aujourd'hui
  3. En 2012 (4.5), ils ont ajouté la prise en charge asynchrone, ce qui n'a rien changé d'autre que l'ajout de nouvelles méthodes qui faisaient les mêmes choses de manière asynchrone.

Revenir à la façon dont l'API 2003 a été définie est un changement qui brisera la compatibilité (ce que les gens ne veulent pas) ou supprimera les fonctionnalités ajoutées au cours de la dernière décennie. Mais l'ajout d'une nouvelle interface à .NET Core avec la conception actuelle est _compatible avec la source_ avec n'importe quelle version .NET. La recompilation est tout ce dont vous avez besoin pour que la plupart du code écrit au cours des 15 dernières années fonctionne. Et vous devrez quand même recompiler pour cibler corefx.

Cette API est stable depuis longtemps. Il pourrait être repensé en tant qu'interfaces si les gens le voulaient. Comme d'habitude, il n'y a pas de problèmes techniques ici, cela se résume à des cicatrices, des préférences et de l'ego.

Pourquoi ne pas ramener les interfaces et les marquer comme obsolètes ?

Bien que cette idée ait été abandonnée, je me demande si des interfaces neutres pour l'assemblage auraient pu aider dans ce genre de situation, voir ceci http://davidfowl.com/assembly-neutral-interfaces/ puis leur implémentation
http://davidfowl.com/assembly-neutral-interfaces-implementation/

Je pense que les interfaces neutres d'assemblage sont un hareng rouge ici; si quelque chose est
arriver, c'est totalement une chose "commune", puisque "commun" existe. Plus ça
est sans objet depuis que la fonctionnalité s'est évaporée.
Le 28 novembre 2015 à 17h38, "Shahid Khan" [email protected] a écrit :

Bien que cette idée ait été abandonnée, je me demande si l'assemblage est neutre
les inferfaces auraient pu aider dans ce genre de situation voir ceci
http://davidfowl.com/assembly-neutral-interfaces/ puis leur
la mise en oeuvre
http://davidfowl.com/assembly-neutral-interfaces-implementation/

-
Répondez directement à cet e-mail ou consultez-le sur GitHub
https://github.com/dotnet/corefx/issues/3480#issuecomment-160323344 .

Ce que j'observe :

  • Les personnes derrière l'idée de CoreClr (nouveau framework brillant) ont un état d'esprit complètement différent de celui des personnes derrière sa mise en œuvre (la rétrocompatibilité avec une base de code vieille de 15 ans est reine).

Ce que je pense:

  • En supprimant les interfaces vous faire empirer les choses.
  • Rien n'est obsolète tant qu'il n'est pas décoré avec [Obsolète]. Et peu importe qui pense quoi à tout moment. C'est le contrat et si vous ne le respectez tout simplement pas, vous ne l'êtes pas.

Ce que je veux:

  • Utilisez des interfaces comme surface de base de l'API plutôt que des classes de base.

Ce que je ressens:

  • Nous sommes à la fin de 2015 et c'est frustrant et triste de voir des gens se disputer à ce sujet.

les interfaces ne peuvent pas être versionnées.

Les interfaces peuvent-elles être facilement versionnées avec l'héritage d'interface ? Et si c'est faire quelque chose de totalement différent ; bien c'est une interface différente.

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

class SomeClass : IOldInterface, INewInterface, IDifferentInterface
{
}

Ne l'appelez pas IInterfaceV2 , IInterfaceV3 il doit expliquer ce qu'il ajoute.

Pour mettre en contexte [Obsolete] l'ancienne interface, et utiliser de nouvelles interfaces et les appeler ce qu'elles sont vraiment ; plutôt que les méthodes non asynchrones qui semblent normales de nos jours.

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

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

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

@abatishchev

Les personnes derrière l'idée de CoreClr (nouveau framework brillant) ont un état d'esprit complètement différent de celui des personnes derrière sa mise en œuvre (la rétrocompatibilité avec une base de code vieille de 15 ans est reine).

Merci d'avoir été clair, il semble qu'il faille le signaler. En général, je pense que les équipes MS se soucient profondément de la compatibilité descendante, qui est vitale pour faire évoluer les deux langages et leurs plates-formes. C'est juste que les décisions concernant System.Data ne sont pas prises en tenant compte de l'écosystème plus large - que ces abstractions de base devraient servir de manière égale.

  • En supprimant les interfaces, vous aggravez les choses.
  • Rien n'est obsolète tant qu'il n'est pas décoré avec [Obsolète]. Et peu importe qui pense quoi à tout moment. C'est le contrat et si vous ne le respectez tout simplement pas, vous ne l'êtes pas.

Précisément.

Concernant le versioning des interfaces. Corrigez-moi si je me trompe mais je pensais que le point de CoreClr est plus fin, le versionnage indépendant ? Changement de rupture ? Boom! Sortie d'une nouvelle version majeure.
Il semble qu'après 15 ans d'expérience en conception, vous allez répéter les mêmes erreurs, mais vous avez maintenant des packages nuget versionnés et publiés de manière indépendante. Les arguments ci-dessus sont identiques au bon vieux cadre monolithique, même s'il ne l'est plus.
Si la compatibilité descendante est indispensable, vous ne pouvez tout simplement pas supprimer ces interfaces. Si ce n'est pas le cas, arrêtons d'en parler et concevons l'API à partir de zéro, cette fois en écoutant les principaux auteurs ORM et d'autres développeurs expérimentés ADO.NET.
Merci.

@abatishchev très bons points. Je me demandais moi aussi : quel est vraiment l'intérêt de l'argument de compatibilité descendante ? Si une nouvelle fonctionnalité est ajoutée à CoreClr, tout ce qui l'utilise ne fonctionnera pas sur .net full, donc pour être sûr, on ne peut utiliser que le comportement commun. (ça n'a jamais bien fonctionné).

Désolé pour le long silence de ma part.

Portage vers .NET Core

Tout d'abord, parlons de l'éléphant dans la pièce, à savoir que .NET Core n'a pas autant d'API disponibles que beaucoup de gens - y compris nous - l'espéreraient.

Je travaille avec mon équipe pour mettre en place un ensemble de documents sur la façon dont nous allons aborder le domaine du portage des ressources existantes vers .NET Core.

Nous prévoyons de porter davantage de fonctionnalités qui n'existent actuellement que dans .NET Framework / Mono vers .NET Core. Ce document expliquera comment nous allons procéder, comment nous priorisons et quels seront les mécanismes. Non seulement j'aimerais que ce travail se fasse au grand jour, mais j'aimerais également permettre à la communauté de nous aider à porter plus de fonctionnalités.

Changements marquants

Il y a un domaine qui cause beaucoup de confusion lorsque les gens parlent de .NET Core. Permettez-moi de préciser une chose :

Ce n'est pas un changement radical si .NET Core a moins d'API que le .NET Framework.

La raison en est que .NET Core est une nouvelle plate-forme et qu'il peut techniquement avoir un ensemble arbitraire d'API. Cependant, bien sûr, nous ne voulons pas d'un ensemble arbitraire -- c'est ce que nous avons fait dans le passé. L'objectif de .NET Core est d'avoir une histoire où les gens peuvent créer des bibliothèques (et avec des applications de console dans une certaine mesure, même des applications) qui s'exécuteront sur .NET Framework et .NET Core. Cela nécessite qu'il y ait un sous-ensemble des deux plates-formes qui soit 100% compatible. Dans ce contexte, vous nous entendrez parler de changements de rupture.

En plus de cela, notre intention est d'avoir une barre de compatibilité élevée dans .NET Core. En d'autres termes, nous ne prévoyons pas d'effectuer des modifications de rupture d'API entre une version d'une API .NET Core et une autre.

Interfaces

L'ajout de membres aux interfaces est - par définition - un changement décisif. Certaines personnes soutiennent que l'impact est faible et qu'il existe des moyens de modéliser cela, mais dans l'état actuel des choses, il s'agit d'un changement binaire et de rupture à la source.

WinRT, qui est basé sur COM et donc fortement dépendant des interfaces, résout ce problème en créant plus d'interfaces, telles que IFoo , IFoo2 , IFoo3 . C'est faisable, mais c'est certainement compliqué sans une fonctionnalité d'exécution ou de langage pour le rendre supportable. Jusqu'à présent, une telle fonctionnalité n'existe pas. Cependant, en tant que membre de l'équipe de conception du langage, je suis très intéressé d'entendre des propositions. D'autres langages et plates-formes ont des idées connexes dans cet espace, et j'examine également activement les options (telles que les mix-ins/traits, l'extension-everything de Swift ou les membres par défaut pour les interfaces).

Puisque nous nous soucions toujours de la compatibilité descendante, nous préférons généralement les types de base abstraits aux interfaces.

Interfaces ADO.NET

Tout cela étant dit, parlons de la demande originale dans ce fil : exposer les interfaces du fournisseur ADO.NET.

Comme l'a expliqué David : nous les avons considérés comme obsolètes lorsque les types de base abstraits ont été introduits, c'était dans .NET 2 / Visual Studio 2005. Il semble que l'on pense fermement que ces interfaces sont essentielles pour porter les frameworks ORM vers .NET Core. Pour moi, cela fournit une preuve suffisante que nous devrions porter les interfaces vers .NET Core.

Cependant, comme pour toutes les nouvelles API, nous devons garder à l'esprit l'un des principaux objectifs de .NET Core, qui consiste à disposer d'une pile en composants. L'interface IDataReader a une dépendance sur DataTable , qui a une dépendance sur DataSet . Comme indiqué dans dotnet/runtime#14302, nous ne sommes pas opposés à l'ajout de la prise en charge de DataTable mais nous considérons DataSet hérité. Cependant, nous pouvons toujours l'ajouter en tant que package séparé, mais dans tous les cas, cela nécessiterait de rompre la chaîne de dépendances des interfaces -> DataTable -> DataSet . Je travaillerai avec @YoungGah pour voir ce que nous pouvons faire là-bas.

Cette approche répondrait-elle aux préoccupations?

Sauf erreur, la seule dépendance DataTable dans IDataReader est la
Méthode GetSchemaTable(), déjà longuement discutée dans le DataTable
chaîne. Je reconnais cependant volontiers que le fait qu'il y ait un
espérons ajouter _quelque_ esprit de fonctionnalité similaire à une date ultérieure (que ce soit
via DataTable ou non) rend très difficile d'exposer cela sur le
interface, car l'extension ultérieure de l'interface est problématique. ce ne serait pas
aussi simple que "supprimer la méthode pour l'instant, ajouter quelque chose d'autre plus tard"
Le 5 décembre 2015 à 00h17, "Immo Landwerth" [email protected] a écrit :

Désolé pour le long silence de ma part.
Portage vers .NET Core

Tout d'abord, parlons de l'éléphant dans la pièce, qui est ce .NET
Core n'a pas autant d'API disponibles que de nombreuses personnes - y compris
nous - j'espère.

Je travaille avec mon équipe pour mettre en place un ensemble de documents sur la façon dont nous allons
pour aborder le domaine du portage des ressources existantes vers .NET Core.

Nous prévoyons de porter davantage de fonctionnalités qui actuellement
existe dans .NET Framework / Mono vers .NET Core. Ce document appellera
comment nous allons le faire, comment nous priorisons et quels seront les mécanismes
être. Non seulement j'aimerais que ce travail se fasse au grand jour, mais j'aimerais aussi
permettre à la communauté de nous aider à porter plus de fonctionnalités.
Changements marquants

Il y a un domaine qui cause beaucoup de confusion lorsque les gens parlent de
.NET Core. Permettez-moi de préciser une chose :

Ce n'est pas un changement radical si .NET Core a moins d'API que .NET
Cadre.

La raison en est que .NET Core est une nouvelle plate-forme et qu'il peut techniquement
avoir un ensemble arbitraire d'API. Cependant, bien sûr, nous ne voulons pas d'un
ensemble arbitraire
http://blogs.msdn.com/b/dotnet/archive/2014/12/04/introducing-net-core.aspx
- c'est ce que nous avons fait dans le passé. L'objectif de .NET Core est d'avoir un
histoire où les gens peuvent créer des bibliothèques (et avec des applications de console à un certain
étendre même les applications) qui s'exécuteront sur .NET Framework et .NET Core. Cette
nécessite qu'il y ait un sous-ensemble des deux plates-formes qui est un 100%
compatible. Dans ce contexte, vous nous entendrez parler de changements de rupture.

En plus de cela, notre intention est d'avoir une barre de compatibilité élevée dans .NET Core.
En d'autres termes, nous ne prévoyons pas d'effectuer des modifications de rupture d'API entre
une version d'une API .NET Core et une autre.
Interfaces

L'ajout de membres aux interfaces est - par définition - un changement décisif.
Certaines personnes soutiennent que l'impact est faible et qu'il existe des moyens de modéliser
cela, mais dans l'état actuel des choses, il s'agit d'un changement binaire et de rupture de source.

WinRT, qui est basé sur COM et donc fortement dépendant des interfaces,
résout ce problème en créant plus d'interfaces, telles que IFoo, IFoo2,
IFoo3. C'est faisable, mais c'est certainement compliqué sans runtime ou
fonction de langue pour le rendre supportable. Jusqu'à présent, une telle fonctionnalité n'existe pas.
Cependant, en tant que membre de l'équipe de conception du langage, je suis très intéressé par
entendre des propositions. D'autres langues et plates-formes ont des idées connexes dans ce
l'espace, et j'étudie également activement les options (telles que
mix-ins/traits, l'extension-everything de Swift ou les membres par défaut pour
interfaces).

Étant donné que nous nous soucions toujours de la compatibilité descendante, nous privilégions généralement
types de base abstraits sur les interfaces.
Interfaces ADO.NET

Tout cela étant dit, parlons de la demande originale dans ce fil:
exposer les interfaces du fournisseur ADO.NET.

Comme l'a expliqué David : nous les avons considérés comme obsolètes lorsque la base abstraite
types ont été introduits, ce qui était dans .NET 2 / Visual Studio 2005. Il semble
que l'on croit fermement que ces interfaces sont essentielles pour
Portez les frameworks ORM vers .NET Core. Pour moi, cela fournit une preuve suffisante
que nous devrions porter les interfaces vers .NET Core.

Cependant, comme c'est le cas pour toutes les nouvelles API, nous devons garder à l'esprit l'un des
principaux objectifs de .NET Core, qui consiste à disposer d'une pile en composants. Les
interface IDataReader a une dépendance sur DataTable, qui a un
dépendance sur DataSet. Comme indiqué dans dotnet/runtime#14302
https://github.com/dotnet/corefx/issues/1039 , nous ne sommes pas opposés à ajouter
prise en charge de DataTable, mais nous ne voulons vraiment pas porter DataSet. Donc
l'ajout des interfaces nécessitera de rompre cette dépendance. je vais travailler avec
avec @YoungGah https://github.com/YoungGah pour voir ce que nous pouvons faire là-bas.

Cette approche répondrait-elle aux préoccupations?

-
Répondez directement à cet e-mail ou consultez-le sur GitHub
https://github.com/dotnet/corefx/issues/3480#issuecomment-162115855 .

Oui, IDataReader a une dépendance sur DataTable qui a une dépendance sur DataSet.

Comme mentionné précédemment, nous ne pouvons pas supprimer les membres des interfaces, nous aurions donc besoin de briser cette dépendance d'une autre manière ; soit en ne portant pas l'interface, soit en brisant la dépendance DataTable -> DataSet.

Cette approche répondrait-elle aux préoccupations?

Oui, la restauration des interfaces ADO.NET, même sans la méthode GetSchemaTable() , résoudrait les lourdes dépendances vis-à-vis des problèmes d'interface ADO.NET auxquels je suis actuellement confronté.

Je suppose que briser la dépendance DataTable -> DataSet si cela signifiait que GetSchemaTable() serait également inclus, serait l'approche préférée pour ceux qui dépendent de GetSchemaTable() (ce serait donc mon vote) - mais Je donnerais plus de poids aux développeurs que cela affecte.

@terrajobst merci pour votre résumé et le partage de vos réflexions.

@terrajobst merci pour le résumé et les explications. Je maintiens Npgsql, donc j'écris du point de vue d'un fournisseur ADO.NET, pas d'un ORM.

Dans .NET Core, Microsoft semble avoir eu le désir de supprimer certaines fonctionnalités héritées de longue date d'ADO.NET, à savoir DataTable/DataSet et les interfaces. Cela crée une API meilleure et plus propre à l'avenir, mais crée déjà un travail substantiel pour les utilisateurs en fonction des interfaces et de l'API DataTable/DataSet.

Personnellement, je pense que tuer DataTable/DataSet est une bonne chose, et qu'une nouvelle et meilleure API de métadonnées devrait être introduite (je pense que c'est vrai même sans tuer DataTable/DataSet). je ne minimise pas
la douleur causée par cette rupture aux consommateurs ORM (et autres), mais une chose à retenir est que s'il y a jamais une opportunité de nettoyer et d'introduire une rupture - .NET Core est cette opportunité.

Un autre facteur frustrant ici est que conserver les interfaces ADO.NET signifie également conserver DataTable/DataSet. En d'autres termes, bien que personnellement, je ne sois pas très sensible au problème des interfaces, les conserver signifie conserver DataTable/DataSet et cela semble plus problématique.

Comme je ne sais pas combien d'ORM existent qui dépendent toujours des interfaces, et je ne sais pas non plus à quel point il leur serait difficile de passer aux classes de base, le choix n'est pas très clair ici. Mais mon intuition est de saisir cette opportunité et de nettoyer les choses même si cela signifie que certaines personnes souffrent...

PS Quoi que vous fassiez, n'empruntez pas la voie de l'explosion de l'interface, c'est-à-dire IFoo2, IFoo3. C'est juste une non-solution.
PPS Si vous décidez de créer une nouvelle API de métadonnées non DataTable dans .NET Core et que vous souhaitez que les bibliothèques .NET Core s'exécutent dans .NET Framework, cela signifie que vous devrez publier un nouveau .NET Framework avec la nouvelle API ainsi que .NET Core.

@terrajobst Merci d'avoir rompu le silence ;). Je pense que le problème principal est qu'il n'y a pas de conception présente pour ADO.NET. Il n'y en a pas eu depuis un certain temps et cela se voit dans diverses parties de l'API qui est un méli-mélo de fonctionnalités rembourrées sans réfléchir pendant plus de quelques minutes (il semble). Je suis d'accord avec @roji à ce sujet : .NET core est une chance unique de faire quelque chose à propos des choses, donc .NET core ne devrait pas être retenu par la règle (à mon avis, idiote) selon laquelle il devrait être rétrocompatible avec .NET plein.

Cela dit, si les choses ne vont pas changer pour le mieux pour ADO.NET (c'est-à-dire qu'il obtient un vrai design où une API générale est conçue qui est ensuite spécialisée dans le SqlClient et non l'inverse ! Donc des fonctionnalités disponibles pas dans SQL Server mais dans d'autres bases de données sont ajoutés à l'API générale et ne sont pas laissés à l'auteur du fournisseur ADO.NET), alors la meilleure chose à faire est de porter autant que possible, y compris les interfaces et nous-mêmes les développeurs tiers #ifdef autour des nids de poule qui seront laissés.

La dépendance DataTable peut cependant être un problème, car l'interface IDataReader rendra difficile la rétrocompatibilité avec .NET full _if_ datatable sous quelque forme que ce soit qui n'est pas porté. Mais je pense que c'est une cause perdue de toute façon. Il a été dit à plusieurs reprises par MS que .NET full ne recevra pas autant de mises à jour / aussi fréquentes que le noyau .NET, donc si quelque chose de _nouveau_ est ajouté au noyau .NET, personne ne peut l'utiliser, car son utilisation rend la bibliothèque immédiatement incompatible avec .NET full. J'ai probablement raté quelque chose ici, alors si c'est le cas, corrigez-moi s'il vous plaît :)

Cela seul rend la situation étrange : il doit y avoir une rétrocompatibilité, mais en pratique, cela semble difficile à réaliser et de toute façon un faux-fuyant. À mon humble avis, si cela est traité en premier, le résultat de cela peut être utilisé pour prendre les bonnes décisions sur ce qu'il faut faire avec les API du noyau .NET, c'est-à-dire les améliorer au lieu de traîner de vieux crufts mal conçus de .NET. Cela ne veut pas dire que toutes les API sont mal conçues, mais avec ADO.NET (comme je l'ai décrit dans un article précédent), les choses n'ont pas été faites correctement depuis de nombreuses années. Faire une rupture nette et implémenter à la place un système qui peut être plus robuste (JDBC est toujours aussi fort, ODBC fonctionne toujours comme il y a 25 ans) et s'adaptant au changement est préférable.

En y réfléchissant un peu plus, le commentaire de

Je comprends que la compatibilité descendante est une exigence qui va bien au-delà de cette discussion spécifique à ADO.NET, je me demande simplement.

C'est l'inverse de @roji : les itérations courtes sont activées en ne cassant pas les API.

Si vous êtes un développeur .Net et que votre build ne cesse de se briser chaque semaine parce que l'API du framework sous-jacent change constamment, vous ne tarderez pas à envisager une autre plate-forme.

Il s'agit donc d'une itération rapide entraînée par des changements ininterrompus.

(édité)
Vous ne pouvez qu'itérer sans interrompre les changements jusqu'à ce que vous deviez, par exemple, ajouter quelque chose à une interface de classe, un changement de comportement (!) .net core rendra votre code non compatible avec .net full, donc dans ce sens il rendra .net core non rétrocompatible avec .net full _pour ce morceau de code_. Quel IMHO revient au noyau .NET aura toujours les mêmes interfaces (classe) et le même comportement que dans .NET complet, jusqu'au dernier octet (ce qui est IMHO insoutenable) ou obtiendra de nouvelles fonctionnalités qui seront rétroportées plus tard (ce qui est littéralement ce que MS a dit btw) à .NET complet, ce qui le rend effectivement non rétrocompatible. Cela dépend de quel côté de la clôture vous êtes bien sûr : si vous dites : « il existe un ensemble commun d'interfaces (de classe) X avec un comportement défini B, et .NET core et .NET full les implémentent et X & B gagneront » t changer dans le futur », cela signifiera toujours qu'il existe un nouveau cadre en dehors de X & B qui apportera de nouvelles choses et qui est précisément là où les choses peuvent changer et aussi où se trouve l'avenir.

On pourrait aller très loin avec cela, par exemple que les interfaces / classes utilisées dans X & B dans le noyau .net sont en fait des enveloppes autour des nouvelles classes / interfaces dans le noyau .NET. Il appartient ensuite au développeur qui les utilise d'utiliser soit X&B, soit les nouveaux avec un meilleur design et sans API en commun avec .NET full.

Comme nous devons déjà #ifdef notre chemin autour des choses manquantes dans X & B, lors de la prise en charge des deux frameworks, à mon humble avis, il est préférable de simplement pouvoir cibler de nouvelles interfaces / classes dans .NET core dès que tôt ou tard le comportement change (peut-être même très subtil , comme une exception différente dans une situation donnée) y apparaîtra de toute façon, donc le "portage" du code vers le noyau .NET avec sa _nouvelle_ API (pas X&B) serait alors mieux. Nous devons de toute façon porter, du moins c'est comme ça que je le vois.

@ryanbnl , je suis d'accord avec @FransBouma. Le fait n'est pas que nous voulions pouvoir casser les API. C'est que le fait de contraindre .NET Core à être exécuté dans .NET Framework signifie que vous ne pourrez jamais rien ajouter à une interface .NET Core ou ajouter un membre abstrait à une classe de base abstraite. Ces deux modifications ne rompent pas vraiment la compatibilité descendante dans un sens réel pour une personne utilisant .NET Core, elles rompent la compatibilité avec .NET Framework.

@roji à moins s'agisse d' un nouveau package de framework externe (par exemple, pas GAC) lorsqu'il peut être compatible à la fois avec Framework et le noyau et s'exécuter sur sa propre cadence ; mais cela pourrait être encore plus de changements pour les fournisseurs d'ORM et le nom System.Data.IDbConnection est déjà pris...

@benaadams c'est un commentaire valide - je n'avais en tête que des API de framework non-nuget telles que ADO.NET. Cependant, ceux-ci semblent couvrir suffisamment d'espace API pour être un problème - .NET Core ne pourra pas faire évoluer l'un d'entre eux (lire : ajouter des méthodes d'interface ou des méthodes abstraites) sans devenir inexécutable

Je ne suis pas sûr de ce que vous voulez dire concernant IDbConnection cependant...

@roji signifiait simplement un nouveau package qui fournissait ces types, par exemple System.Data.Database ; pour rester compatible à la fois avec le noyau et le complet, ne pouvait pas redéfinir les types qui seraient des GAC dans le cadre complet ou cela entrerait en conflit.

Sur le point nuget ; il n'y a aucune raison pour que cela ne puisse pas vivre en nuget à la fois pour le plein et le noyau; et déprécier la publication actuelle de l'API System.Data 4.6.1+ ?

Cela causerait plus de douleur maintenant; mais une certaine compatibilité est déjà cassée, où elle supprime les interfaces, ou ne supprime que DataSet donc des remaniements doivent déjà être effectués pour coreclr par les fournisseurs ORM.

Une toute nouvelle api qui vivait dans nuget et en dehors du framework GAC pourrait être rétrocompatible pour une utilisation avec netstandard1.2, par exemple 4.5.2+, coreclr, UWP, mono/Xamarin, etc. Bien que ce serait un peu plus pénible maintenant - mais c'est probablement un meilleur moment que plus tard.

Étant donné que les nouvelles API sont en jeu pour achema et autres, indiquant que DataSet ne viendra pas (ou DataTable ), cela devrait-il être fermé ? Il semble que les classes de base soient la voie à suivre en fonction des commentaires dans dotnet/corefx#5609 et du transfert de type, ce qui signifie que les interfaces n'ont aucune utilité compte tenu de GetSchemaTable() et que d'autres ne sont pas là pour les apporter pour la compatibilité ... est-ce juste de dire ?

Faut-il fermer quoi ? Si nous ne pouvons pas avoir GetSchemaTable() cause de la dépendance DataTable/DataSet, c'est une chose, mais les interfaces doivent toujours être restaurées (sans GetSchema si nécessaire) et faciliter le portage des bases de code existantes avec des dépendances profondes. Les interfaces manquantes sont un bloqueur, j'attends toujours une version avec elles avant de pouvoir commencer le travail pour supporter dnx/core.

Je suis d'accord avec @mythz , les interfaces sont un autre sujet et très important. Peut-être pas pour la plupart des utilisateurs, mais ces mêmes utilisateurs utilisent du code écrit par un petit groupe et ce code _est_ basé sur ces interfaces (ainsi que d'autres fonctionnalités ADO.NET manquantes importantes comme DbProviderFactory).

Pour être honnête, avec la poussée extrême vers un label « RTM », j'ai peu d'espoir que nous obtiendrons une API solide avec 1.0. Ce sera à nouveau comme .NET 2.0 : toutes les erreurs commises par la première version seront alors corrigées.

@FransBouma

L'ajout des interfaces à .NET Core serait un changement supplémentaire. Donc même s'il ne fait pas la coupe pour V1, il pourrait être ajouté dans n'importe quelle version suivante, même 1.1.

toutes les erreurs commises par la première version seront alors corrigées.

Ne vous offensez pas, mais c'est ainsi que fonctionne le logiciel.

@terrajobst

Donc même s'il ne fait pas la coupe pour V1, il pourrait être ajouté dans n'importe quelle version suivante, même 1.1.

ouais, ce n'est pas que ce n'est techniquement pas possible, c'est que les résultats de le faire (ou l'absence de le faire) ont des conséquences (de grande envergure), dont Microsoft n'est pas celui qui souffre, c'est nous. Jusqu'à présent, j'ai vu peu d'apathie pour cela. C'est cool et excitant de travailler sur de nouveaux frameworks, mais ce n'est pas développé dans une salle blanche pour un nouveau public. Ce n'est pas non plus le cas, il n'y a pas d'histoire à apprendre, bien au contraire.

Ne vous offensez pas, mais c'est ainsi que fonctionne le logiciel.

Tu vois, c'est exactement ce que je veux dire plus haut : tu n'es pas celui qui doit faire face aux conséquences de tes décisions, je dois le faire. Et j'ai déjà traité les conséquences d'une décision similaire de vos prédécesseurs, alors je vous ai prévenu pour que vous ne commettiez pas la même erreur.

Je sais comment fonctionnent les logiciels, je suis développeur de logiciels professionnel depuis plus de 21 ans. J'ai donné mes conseils honnêtes, non pas en tant que novice mais en tant qu'expert aguerri dans ce domaine particulier. Vous pouvez en faire ce que vous voulez, c'est juste que j'espère que vous y réfléchirez à deux fois avant de prendre une décision à la légère ici, car les conséquences sont lourdes, et comme je l'ai dit : nous devons nous en occuper, pas vous.

Même une erreur peut être réparée plus tard, mais elle n'est pas encore commise, c'est une bonne raison de ne pas la faire en premier, n'est-ce pas ?

Vous réagissez de manière excessive. Je doute que les effets de cela aient les mêmes conséquences que l'ancien .NET.

Avec coreclr intégré à chaque application, l'héritage a une signification très différente. Comme à peu près personne ne se soucie de savoir si les fonctionnalités d'asp.net mvc 5 ne sont pas rétroportées sur mvc 4 ou 3. L'héritage ici aura une signification différente, et il y a un historique dans d'autres projets pour le montrer.

Heureusement que

@nvivo S'il vous plaît, n'essayez pas de minimiser les conséquences que je dois gérer, car vous n'avez pas à les gérer, mais je le fais.

Merci @FransBouma de m'avoir mis à ma place. C'était mon erreur de penser que je pouvais commenter la question. Vous êtes certainement plus qualifié que moi pour savoir quel genre de choses affectent mon travail.

En fait, même si j'ai ouvert le problème, cela n'a absolument aucun effet sur mon travail ou sur les choses qui me tiennent à cœur. Je pensais juste aux pauvres développeurs comme vous qui font tout le travail dur sur la planète.

Je suis vraiment content que des gens comme vous soient là pour s'occuper des problèmes difficiles. N'hésitez pas à nous dire encore et encore et encore (et encore) à quel point les problèmes auxquels vous devez faire face sont plus importants.

Merci @FransBouma.

_soupir_ Où est-ce que je dis tout ça ? Tout ce que je dis, c'est s'il vous plaît, ne minimisez pas les choses, comme vous le faites avec "vous réagissez de manière excessive", je ne pense pas que je réagis de manière excessive. Par « vous n'avez pas à vous en occuper », je veux dire : les conséquences pour _moi_. Parce que je sais ce que c'est, je réagis comme je l'ai fait. Apparemment, c'est "exagéré".

Mais peu importe.

Nous avons des réponses à ce problème ici et ici .

La réponse officielle est : les interfaces ne seront pas sur .NET Core 1.0, et bien que peu probable, elles peuvent être envisagées pour les futures versions sous une forme différente de celle qui existait sur .NET.

Je ferme ce sujet car la question initiale a été traitée.

@nvivo Merci, mais il est préférable de laisser les réponses officielles aux personnes réellement responsables du projet qui sont également capables de résoudre elles-mêmes les problèmes une fois qu'elles ont décidé qu'elles ont été résolues.

@terrajobst Existe-t-il une réponse/un calendrier officiel mis à jour pour les interfaces ? et quelle est la meilleure façon de suivre cet élément de travail à l'avenir ? devrions-nous ouvrir un nouveau numéro ou continuerez-vous à fournir des mises à jour ici ?

Laissons cela ouvert pour le moment. La façon dont je le vois, la réponse n'était pas "n'exposons pas les interfaces". La réponse était "trouvons un moyen de les exposer mais réfléchissons à ce que cela signifie pour la dépendance DataTable".

Désolé de vous répondre si tard. Après avoir discuté de diverses options au sein de notre équipe, nous avons décidé de ramener les interfaces avec une classe vide de DataTable. Ce n'est pas une solution idéale, mais étant donné le calendrier de RTM, cette approche garantira que nous pourrons rechercher des options viables autour de DataTable/DataSet à l'avenir. Nous allons essayer d'intégrer les interfaces pour System.Data.Common par v1 RTM ; SqlClient n'implémentera pas les interfaces par v1. Merci pour vos retours et votre patience. Vos commentaires sont un élément clé pour faire de la pile de données un produit viable.

@YoungGah merci pour la mise à jour, si les classes DataTable ne sont que des espaces réservés vides, qu'est-ce qui nécessite autant de temps/d'efforts (c'est-à-dire les retenir) pour être implémentés par SqlClient v1?

@mythz Le coût consiste à implémenter les interfaces dans le type de base / à les transmettre aux méthodes existantes. Le coût devrait être minime, mais généralement les choses se présentent :sourire:

Nous avons ajouté les interfaces suivantes à .Net CoreFX dans System.Data.Common

IDataParameter
IDataParameterCollection
IDataReader
IDataRecord
IDbCommande
IDbConnexion
IDbDataParameter
IDbTransaction

Cela a été fait dans le PR https://github.com/dotnet/corefx/pull/6359

@saurabh500 Super truc, merci !

:+1:

:+1:

Impressionnant; y a-t-il un jalon pour que cela atteigne le nuget? rc3 ?

Le 25 février 2016 à 02:54, Saurabh Singh [email protected]
a écrit:

Nous avons ajouté les interfaces suivantes à .Net CoreFX dans System.Data.Common

IDataParameter
IDataParameterCollection
IDataReader
IDataRecord
IDbCommande
IDbConnexion
IDbDataParameter
IDbTransaction

Cela a été fait dans le PR dotnet/corefx#6359 https://github.com/dotnet/corefx/pull/6359

-
Répondez directement à cet e-mail ou consultez-le sur GitHub
https://github.com/dotnet/corefx/issues/3480#issuecomment-188577701 .

Salutations,

Marc

Comme commenté sur le PR, nous devons comprendre pourquoi il n'y a pas de méthodes asynchrones sur ces interfaces. Comme cela a été proposé, il s'agit essentiellement d'une version réduite des interfaces ADO.NET 1.1, et je ne pense pas que l'idée devrait être uniquement la compatibilité avec l'ancien code.

Les interfaces doivent se concentrer sur l'état actuel d'ado.net, car les méthodes asynchrones doivent être le moyen par défaut d'accéder à n'importe quelle base de données aujourd'hui. Sans prise en charge réelle des méthodes asynchrones, ces interfaces sont inutiles pour le développement moderne
développement.

Et même en incluant les méthodes asynchrones de .NET 4.5, certaines méthodes supplémentaires, telles que DbTrabsaction.CommitAsync, devraient également être ajoutées.

Le fournisseur postgres a ajouté des méthodes supplémentaires telles que CommitAsync à leur API, qui sont très utiles et nécessaires.

Les interfaces actuelles sont très bien telles qu'elles sont. L'implication de les changer est tout simplement trop grande.

Le modèle asynchrone est assez différent du modèle synchrone et comme vous le savez peut-être, si vous optez pour le modèle asynchrone, vous devriez le faire jusqu'au bout. Par conséquent, il n'y a vraiment aucune raison d'avoir les mêmes interfaces pour les deux API. Créez-en de nouveaux pour l'API asynchrone.

Si l'équipe .NET souhaite fournir une API plus moderne, pourquoi ne pas simplement créer une nouvelle API qui ne s'appelle pas ADO.NET ? Aucun héritage à entraver et aucune plainte de la communauté. Cela correspond également bien à la façon dont dnx va être distribué? c'est-à-dire des packages indépendants.

:+1: sur les interfaces, bon compromis.

Je ne pense pas que l'idée devrait être uniquement la compatibilité avec l'ancien code.

C'est l'idée entière ici. Sinon, les classes de base conviendraient. C'est beaucoup de problèmes de portage que nous voulons éviter.

Sans prise en charge réelle des méthodes asynchrones, ces interfaces sont inutiles pour le développement moderne.

Je ne suis pas d'accord avec cela, mais je ne suis pas en désaccord avec une version asynchrone des interfaces nécessairement (que personne n'implémente aujourd'hui). Ce serait une nouveauté. Nous ne pouvons pas ajouter rétroactivement des membres aux interfaces existantes, cela casse beaucoup trop de choses. Avoir un IDbReaderAsync ou quelque chose n'est pas fou IMO, mais c'est une discussion différente.

Je crois fermement que les méthodes async ne devraient _pas_ être sur les classes de base, si l'implémentation par défaut est un wrapper de synchronisation - c'est activement mauvais et inutile. S'il y a une autre proposition, qu'il en soit ainsi, mais encore une fois : cela devrait être une autre question de toute façon.

Ok, peut-être que je me suis mal exprimé ici ou que j'étais trop fort avec mes mots.

Je suis en faveur d'une interface supplémentaire pour async si nécessaire. Ce avec quoi je ne suis pas d'accord, c'est d'avoir quelque chose qui définit un contrat officiel pour ADO.NET (c'est ce que sont les interfaces) mais qui ne contient aucune méthode asynchrone.

Mais alors, avoir des interfaces alternatives pour les méthodes asynchrones causerait probablement d'autres problèmes...

Je crois fermement que les méthodes asynchrones ne devraient pas être sur les classes de base, si l'implémentation par défaut est un wrapper de synchronisation - c'est activement mauvais et inutile.

Je suis d'accord, c'est la principale raison pour laquelle la plupart des fournisseurs ne prennent pas la peine de mettre en œuvre une véritable API asynchrone. Mais changer cela casserait beaucoup plus de code et causerait probablement beaucoup plus de bruit que la suppression d'interfaces, car les classes de base sont l'API réelle des fournisseurs depuis 2.0.

La mise à niveau d'une bibliothèque pour n'utiliser aucune des interfaces 1.1 aurait un impact presque nul par rapport à la suppression de tout le code asynchrone écrit au cours des dernières années, ce qui serait désastreux. Le compromis est d'avoir les deux. Tout code écrit aujourd'hui devrait utiliser des API asynchrones, donc le laisser de côté n'a aucun sens.

Tout code écrit aujourd'hui devrait utiliser des API asynchrones.

Je ne veux pas blesser trop durement, mais ce monde idéal est très éloigné de la réalité. Async est très omniprésent et contagieux. Vous ne pouvez tout simplement pas vous fier uniquement aux API asynchrones dans les bibliothèques et vous attendre à ce que des applications entières soient des consommateurs asynchrones (en changeant un _ton_ de leur code pour qu'il soit également asynchrone) sur un coup de tête. Sync -> Async partout est également très mauvais pour de nombreuses raisons d'impasse et d'efficacité. Il y aura du code synchrone écrit pendant de nombreuses années à venir.

Il y a un fort besoin pour les deux API. Le point est : ne supprimons pas les actuels ou ne retardons pas leur présence pour un nouvel ensemble hypothétique et pas encore conçu. Nous pouvons nous soucier du deuxième/nouveau ensemble indépendamment.

La mise à niveau d'une bibliothèque pour n'utiliser aucune des interfaces 1.1 aurait un impact presque nul par rapport à la suppression de tout le code asynchrone écrit au cours des dernières années

A quoi fais-tu référence ? Il n'y a pas eu d'API asynchrone pour qu'un tel code existe. Si vous comptez sur de telles API, elles ne reposent pas sur une classe de base ou une interface, mais directement sur un fournisseur. Cela ne sera pas affecté par cela.

Tout code écrit aujourd'hui devrait utiliser des API asynchrones, donc le laisser de côté n'a aucun sens.

Laisser de côté beaucoup de choses n'a pas de sens... sauf pour le fait que nous sommes tous limités par les ressources (surtout le temps). Je ne crois pas que quiconque ait omis quoi que ce soit de manière permanente. Rien n'est hors de la table. Il n'a tout simplement pas encore été atteint. J'ouvrirais un autre problème spécifiquement pour démarrer une spécification sur les interfaces asynchrones pour une génération future.

A quoi fais-tu référence ? Il n'y a pas eu d'API asynchrone pour qu'un tel code existe. Si vous comptez sur de telles API, elles ne reposent pas sur une classe de base ou une interface, mais directement sur un fournisseur. Cela ne sera pas affecté par cela.

.NET 4.5 a introduit des méthodes asynchrones sur les classes de base du fournisseur. C'était en 2012, il y a presque 4 ans, il fait donc partie de l'API du fournisseur ADO.NET depuis un certain temps. Entity Framework 6 (publié en 2013) dépend de ces API asynchrones pour tous les fournisseurs.

Les méthodes asynchrones font déjà partie d'ADO.NET depuis suffisamment longtemps que beaucoup de gens crieraient si cela n'était pas inclus dans .NET Core. J'ai _legacy code_ qui utilise des méthodes asynchrones dans ADO.NET.

Je préconise que, puisqu'ils font _déjà_ partie d'ADO.NET, cela devrait également être présent sur la nouvelle API d'interface.

Si les gens veulent (et ils devraient) utiliser les API asynchrones, ils peuvent déjà le faire
qu'avant ce changement en utilisant les types de base. En définitive, la demande
la prise en charge des interfaces a été faite pour des raisons de compatibilité descendante ;
l'ajout de méthodes à une interface _souffle complètement cela hors de l'eau_.
Cela dit, c'est en fait à peu près possible en tant que _méthodes d'extension_ et
vérification de type par rapport aux types de base abstraits, mais... assez moche et pas
vaut la peine OMI.

Donc; version courte : je ne peux personnellement pas accepter l'ajout d'async au
interfaces, car cela détruit la seule chose pour laquelle nous les voulions dans le premier
endroit. Si vous voulez async : vous devez coder par rapport aux classes de base, ou utiliser
des outils qui masquent ces détails pour vous.

Je préconise que, puisqu'ils font déjà partie d'ADO.NET, cela devrait également être présent sur la nouvelle API d'interface.

Vous ne comprenez absolument pas le but de ces interfaces ADO.NET qui est de maintenir la compatibilité avec le code existant. Ce ne sont pas des _nouvelles_ interfaces, ce sont des _existantes_ interfaces. Si vous souhaitez accéder aux API les plus récentes, référencez les types de base concrets.

@nvivo Excuses, je ne vous suis tout simplement pas - je parlais des API _interface_ - celles-ci n'ont jamais existé. Les types de base ont déjà toutes les mêmes méthodes *Async - y a-t-il quelque chose de spécifique qui manque ? Je pense que vous soutenez qu'ils devraient être regroupés dans des interfaces... oui, bien sûr, mais c'est un autre problème que je vous encourage à ouvrir.

Je préférerais de loin qu'ils soient une interface depuis le début, car les implémentations de base nécessaires pour faire fonctionner l'approche actuelle (async sur la synchronisation) sont de terribles compromis pour faire fonctionner l'ensemble de l'approche. Mais, on ne peut pas non plus jouer sur les deux tableaux : soit ils se déplacent vers les interfaces, soit ils sont présents (comme c'est le cas actuellement) pour minimiser les ruptures.

Oui, je pense que nous tournons en rond ici. Je l'ai déjà dit, je ne pense pas que les interfaces devraient être ajoutées _juste_ pour aider au portage du code. Du point de vue de la compatibilité, les classes de base sont l'API officielle d'ADO.NET depuis 2005, et c'est ce que les fournisseurs implémentent. Tout ce qui utilise un IDbCommand ou un IDbConnection pourrait facilement être porté (et aurait dû être porté) pour utiliser des classes de base avec une recherche/remplacer et n'avoir aucun inconvénient.

Je sais que vous n'êtes pas un fan d'ifdefs, mais le support pour une nouvelle plate-forme ne fera de toute façon qu'une partie de la migration.

Je suis d'accord que cela aurait dû être des interfaces depuis le début, mais comme ce n'était pas le cas, j'aimerais que ce problème ne se répète pas. Si des interfaces sont ajoutées, elles devraient au moins représenter l'API actuelle, et non ce qu'elles étaient il y a dix ans. Les méthodes asynchrones font partie intégrante de l'API actuelle et c'est la direction que prend Microsoft depuis un certain temps. Il serait toujours compatible avec la source, juste plus complet.

@mgravell

Si les gens veulent (et ils devraient) utiliser les API asynchrones, ils peuvent déjà le faire _avant ce changement_ en utilisant les types de base.

Il ne s'agit pas de pouvoir faire quoi que ce soit. Il s'agit d'architecture. Les interfaces sont des contrats, .NET Core est un nouveau framework qui ajoute ce contrat à une version repensée de l'API.

Le noyau .NET ne devrait pas ajouter de contrat officiel à une nouvelle API uniquement pour aider à migrer du code vraiment ancien, alors que la plupart des autres éléments manqueront de toute façon. Si c'est un problème, les gens ne recherchent tout simplement pas assez les raisons pour lesquelles ils devront de toute façon changer leur code.

Si c'est tout ce que l'équipe fait, alors ce n'est pas grave... c'est juste un mauvais choix IMO.

Tout ce qui utilise un IDbCommand ou un IDbConnection pourrait facilement être porté (et aurait dû être porté) pour utiliser des classes de base avec une recherche/remplacer et n'avoir aucun inconvénient.

Faux. Les problèmes ont été discutés à plusieurs reprises dans ce fil de discussion par plusieurs auteurs de bibliothèques ayant une expérience de première main affectée par cela.

Je sais que tu n'es pas fan des ifdefs

Toute solution exigeant que les clients finaux utilisent ifdefs est une expérience de développement brisée et non-starter, c'est-à-dire qu'il n'y aura jamais de produit réussi obligeant les clients à salir leur code avec #defs lorsque des alternatives existent.

Si des interfaces sont ajoutées, elles doivent au moins représenter l'API actuelle

Ce ne sont pas de nouvelles interfaces, ce sont des interfaces restaurées. Les API actuelles et futures sont les classes de base, pas ces interfaces. Il ne devrait y avoir aucun problème ici, vous pouvez oublier que ces interfaces existent et continuer à utiliser les types de base comme avant la restauration de ces interfaces.

Il n'y a plus de nouvelle valeur ajoutée à ce fil. Les interfaces ADO.NET existantes ont été restaurées afin que ce fil puisse être mis au repos. La seule chose nécessaire à partir de ce fil est les mises à jour de DataTable et GetSchemaTable() en ce qui concerne les interfaces existantes. Si vous souhaitez proposer des modifications architecturales ou plaider en faveur de nouvelles interfaces, ouvrez un nouveau problème - ce qui empêchera tout le monde dans cette liste d'être spammé.

@mythz acceptons d'être en désaccord.

En ajoutant simplement mes 2 cents en tant qu'autre développeur ORM, les classes abstraites sont toujours une odeur de code lorsqu'elles ne sont pas soutenues par une interface. J'adorerais voir de nouvelles interfaces fournies pour faire correspondre les classes abstraites et les signatures de méthode surchargées avec une API d'interface d'exigence minimale.

Bravo à la communauté d'avoir pris la parole.

les classes abstraites sont toujours une odeur de code lorsqu'elles ne sont pas soutenues par une interface

@psibernetic Pouvez-vous m'aider à comprendre cette déclaration ? Qu'en est-il de cette odeur de code ?

@psibernétique

Les interfaces et les classes abstraites nous donnent un contrat, les deux nous donnent une abstraction et une bonne définition pour l'API. Les interfaces sont les plus utiles lors de l'implémentation de classes qui pourraient implémenter plusieurs interfaces ou qui sont des sous-classes d'une autre classe de base (en supposant que c'est un très gros avantage de cette classe de base). Dans ce cas en particulier, les classes concrètes pour Connection, Command, etc. pour des fournisseurs spécifiques ont une forte relation IS A avec les définitions d'API abstraites. Je ne peux vraiment pas imaginer un scénario où un développeur doit ajouter une implémentation concrète pour IDbConnection ou IConnection à une sous-classe. Le presque seul scénario sera de nouvelles classes qui dérivent uniquement pour la classe abstraite et "dupliquer" la même définition sur une Interface est plus de travail (inutile) pour le concepteur d'API.

Voyez-vous un avantage ou un scénario spécifique et concret à avoir deux abstractions égales ? Quand l'interface offre-t-elle un avantage pratique et réel par rapport à la classe abstraite dans cette conception d'API spécifique ?

Le seul avantage auquel je peux penser pour les interfaces est la compatibilité descendante dont nous avons besoin avec les anciennes pour casser moins de code en cours d'exécution dépendant de ces interfaces. Si nous n'avions pas les anciennes interfaces, je suis presque sûr que les classes abstraites suffiront.

@eocampo Vous avez raison de dire que les classes abstraites fournissent probablement une abstraction et des contrats "assez bons". J'essaie toujours de fournir des interfaces très étroites qui représentent les actions qui peuvent être prises telles que IAsyncCommand et autres. Cela permet à mes frameworks d'être connectés d'une manière qui n'a peut-être pas été prise en compte au moment de la conception du framework avec moins de chance de terribles NotSupportedExceptions ou NotImplementedExceptions.

@davkean L'odeur du code est que dans la plupart des cas, mais pas tous, vous demandez à un implémenteur d'implémenter ou d'hériter d'un ensemble complet de fonctionnalités de base qui peuvent ne pas être pertinentes. Je me souviens avoir vu des implémentations IDataReader qui lisent à partir d'un cache ou en mémoire à la place. Je ne sais pas si la classe abstraite DbDataReader le permettrait, mais le nom implique non.

Le modèle des meilleures pratiques suivi principalement dans dot net a été les interfaces d'exposition et hérite des classes de base, n'est-ce pas ?

Le modèle des meilleures pratiques suivi principalement dans dot net a été les interfaces d'exposition et hérite des classes de base, n'est-ce pas ?

@psibernetic Eh bien pas toujours. Par exemple, cette recommandation sur le site MSDN existe depuis plus d'une décennie. Et cette directive est très courante à partir de .Net Framework 2.0 au moins.

C'est également une bonne référence des lignes directrices pour la conception de bibliothèques dans .Net depuis les premiers jours :

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

Quoi qu'il en soit, je pense que la discussion difficile ici porte sur deux sujets maintenant :

a) Les interfaces sont uniquement destinées à la rétrocompatibilité ou pouvons-nous « repartir de zéro » (briser le code) pour permettre une interface et une conception d'API plus propres.
b) Combien pouvons-nous aller pour un design moderne et épuré au prix de ne pas être compatible avec le framework .Net complet. (Compatibilité spécifiquement entre .Net Core et Full core sur l'accès aux données [pas le niveau le plus bas et la compatibilité obligatoire])

De mon point de vue, si nous avons les classes de base abstraites comme contrat principal et préféré, alors les _interfaces_ doivent correspondre aux anciennes juste pour la compatibilité. Je comprends que @nvivo a déjà déclaré qu'après .Net 2.0 le contrat officiel était les classes de base abstraites donc nous _pourrions_ penser que les interfaces ne résoudront pas le problème de compatibilité mais @mythz et @mikeobrien avaient également fourni des données

Pour arrêter de spammer et de discuter des sujets ici, nous devrons relire cette longue conversation et je ne sais pas si nous pouvons nous mettre d'accord sur la LISTE des sujets spécifiques que nous abordons ou si c'est une bonne idée de créer deux ou trois nouveaux problèmes pour chaque sujet spécifique. Je suis plutôt de la première suggestion car il y a beaucoup de bons points ici. Je n'ai pas une bonne idée de la façon dont nous pouvons résumer tout cela et éliminer certains bruits (même le mien).

En parlant d'interfaces, est-il prévu de rendre enfin certaines parties de System.Data génériques ? Cela m'a toujours dérangé que System.Data n'ait jamais vraiment mis à jour son API au-delà de .NET 1.1, obligeant les gens à utiliser des hacks comme la méthode d'extension .AsEnumerable() pour obtenir un IEnumerableà partir d'un DataTable. Pourquoi des collections telles que DataRowCollection n'ont-elles pas été mises à niveau pour implémenter les interfaces génériques alors que tout le reste du framework l'a fait lors de la sortie de la 2.0 ?

Y aura-t-il un stub System.Data avec des redirections de type ? J'ai besoin d'utiliser ODP.NET mais maintenant je ne peux pas.

Créé dotnet/corefx#7874

@mgravell @ploeh Les classes de types implicites "Rickasaurus" étaient à l'horizon (pour F# au moins, pas sûr de C# ou .NET en général https://news.ycombinator.com/threads?id=Rickasaurus). Si c'est le cas pour tous les .NET, cela résoudra-t-il le problème ?

Je ne suis pas un expert en Haskell, mais je crois comprendre qu'ils vous permettraient de vous équiper d'un simple IDbConnection , IDbConnectionAsync et de toute future interface partagée après coup sans casser la source ou compatibilité binaire, et sans forcer les fournisseurs tiers à tout implémenter. Ceci, tout en conservant une moquerie facile.

Est-ce une compréhension correcte? Si oui, y a-t-il une chance que cette fonctionnalité arrive sur .NET pour de vrai ?

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

chunseoklee picture chunseoklee  ·  3Commentaires

matty-hall picture matty-hall  ·  3Commentaires

Timovzl picture Timovzl  ·  3Commentaires

yahorsi picture yahorsi  ·  3Commentaires

omajid picture omajid  ·  3Commentaires