Je voudrais recueillir autant d'informations que possible au sujet de l'API de gestion des versions .NET/CLR, et, en particulier, les changements de l'API de faire ou de ne pas casser les applications clientes. Tout d'abord, définissons quelques termes:
API changement - un changement dans le visible publiquement définition d'un type, y compris l'une quelconque de ses membres publics. Cela inclut changer le type et le nom des membres, en changeant de type de base d'un type, ajout/suppression d'interfaces à partir de la liste de la mise en œuvre des interfaces d'un type, ajout/suppression de membres (y compris les surcharges), la modification des états de visibilité, le changement de nom de la méthode et des paramètres de type, ajouter des valeurs par défaut pour les paramètres de la méthode, de l'ajout/suppression d'attributs sur les types et les membres, et en ajoutant/supprimant des paramètres de type générique sur les types et les membres (ai-je raté quelque chose?). Cela ne comprend pas les changements d'états des corps, ou de toute modification à des membres privés (c'est à dire en ne tenant pas compte de la Réflexion).
Binaire au niveau de pause - une API changement qui en résulte dans le client assemblées compilé avec l'ancienne version de l'API potentiellement pas de chargement avec la nouvelle version. Exemple: retrait d'un membre de la classe.
Au niveau de la Source pause - une API changement qui se traduit dans le code existant écrit pour compiler avec d'anciennes version de l'API peuvent ne pas être de la compilation avec la nouvelle version. Déjà compilé client assemblées travail comme avant, cependant. Exemple: l'ajout d'une nouvelle surcharge qui peut entraîner une ambiguïté dans les appels de méthode qui étaient sans ambiguïté précédente.
Au niveau de la Source de calme sémantique du changement - une API changement qui se traduit dans le code existant écrit pour compiler avec d'anciennes version de l'API tranquillement changer sa sémantique, par exemple par l'appel d'une méthode différente. Le code doit cependant continuer à compiler sans avertissements/erreurs, et a été compilé assemblées devrait fonctionner comme avant. Exemple: mise en œuvre d'une nouvelle interface d'une classe existante que les résultats dans une autre surcharge être choisi lors de la résolution de surcharge.
Le but ultime est de catalogize autant de la rupture et la tranquillité de la sémantique de l'API de changements que possible, et de décrire exactement l'effet de rupture, et quelles sont les langues et ne sont pas affectés par elle. Pour développer sur le dernier: alors que certains changements affectent toutes les langues universelle (par exemple, l'ajout d'un nouveau membre à une interface de briser les implémentations de cette interface dans n'importe quelle langue), certains de besoin très spécifique de la langue de la sémantique d'entrer dans le jeu pour faire une pause. Cette plupart implique généralement la surcharge de méthode, et, en général, n'importe quoi avoir à faire avec les conversions de type. Il ne semble pas être un moyen de définir le "plus petit dénominateur commun" ici même pour CLS-conforme langues (c'est à dire ceux qui satisfont au moins aux règles de CLS "consommateur", tel que défini dans les spécifications CLI) - bien que je vais apprécier si quelqu'un me corrige comme étant mal ici - donc cela devra aller de la langue par langue. Ceux qui présentent le plus d'intérêt sont naturellement ceux qui viennent avec .NET: C#, VB et F#; mais d'autres, comme IronPython, IronRuby, Delphi Prism, etc sont également pertinents. La plus un angle cas, il est le plus intéressant, il sera, comme des membres de la suppression sont assez évidentes, mais de subtiles interactions entre par exemple la surcharge de méthode, en option/paramètres par défaut, lambda, l'inférence de type, et les opérateurs de conversion peut être très surprenant à la fois.
Quelques exemples pour lancer ce:
L'ajout de nouvelles surcharges de méthode
Genre: au niveau de la source pause
Langues concernées: C#, VB, F#
API avant modification:
public class Foo
{
public void Bar(IEnumerable x);
}
API après modification:
public class Foo
{
public void Bar(IEnumerable x);
public void Bar(ICloneable x);
}
Exemple de client code du travail avant le changement et cassé après:
new Foo().Bar(new int[0]);
L'ajout de nouveaux la surcharge de l'opérateur de conversion implicite
Genre: au niveau de la source de rupture.
Langues concernées: C#, VB
Langues qui ne sont pas touchés: F#
API avant modification:
public class Foo
{
public static implicit operator int ();
}
API après modification:
public class Foo
{
public static implicit operator int ();
public static implicit operator float ();
}
Exemple de client code du travail avant le changement et cassé après:
void Bar(int x);
void Bar(float x);
Bar(new Foo());
Notes: F# n'est pas cassé, parce qu'il n'a pas de langue de niveau de soutien pour les opérateurs surchargés, ni explicite, ni implicite, qui ont toutes deux pour être appelé directement comme op_Explicit
et op_Implicit
méthodes.
L'ajout de nouvelles méthodes d'instance
Genre: au niveau de la source de calme sémantique de changement.
Langues concernées: C#, VB
Langues qui ne sont pas touchés: F#
API avant modification:
public class Foo
{
}
API après modification:
public class Foo
{
public void Bar();
}
Exemple de code client qui souffre d'un calme sémantique changement:
public static class FooExtensions
{
public void Bar(this Foo foo);
}
new Foo().Bar();
Notes: F# n'est pas cassé, parce qu'il n'a pas de langue de support au niveau de l' ExtensionMethodAttribute
, et nécessite CLS méthodes d'extension pour être appelé en tant que méthodes statiques.