674 votes

C# Interfaces. Implémentation implicite par rapport à l’implémentation explicite

Quelles sont les différences dans la mise en œuvre des interfaces implicitement et explicitement en C#?

Quand devriez-vous utiliser l'implicite et quand devez-vous utiliser explicite?

Existe-il des avantages et/ou inconvénients de l'un ou de l'autre?


Microsoft directives officielles (à partir de la première édition du Cadre des lignes Directrices de Conception) stipule que l' utilisation explicite des implémentations ne sont pas recommandés, car il donne le code de comportement inattendu.

Je pense que cette directive est très valable dans un pré-Cio-temps, lorsque vous ne passez pas les choses autour de lui comme des interfaces.

Quelqu'un pourrait-il toucher à cet aspect?

518voto

mattlant Points 9136

Est implicite lorsque vous définissez votre interface par l'intermédiaire d'un membre de votre classe. Explicite est lorsque vous définissez les méthodes au sein de votre classe sur l'interface. Je sais que cela semble confus, mais voici ce que je veux dire: IList.CopyTo serait implicitement implememnted:

public void CopyTo(Array array, int index)
{
    throw new NotImplementedException();
}

et explicitement que:

void ICollection.CopyTo(Array array, int index)
{
    throw new NotImplementedException();
}

La différence étant que, implicitement, est accessible devant votre classe, vous avez créé quand il est lancé en tant que classe ainsi que lors de la distribution de l'interface. Explicite implentation lui permet d'être accessible lors de la fonte que l'interface elle-même.

MyClass myClass = new MyClass(); // Declared as concrete class
myclass.CopyTo //invalid with explicit
((IList)myClass).CopyTo //valid with explicit.

J'utilise explicite principalement pour garder la mise en œuvre propre, ou quand j'ai besoin de deux implemetations. Mais peu importe j'ai rarement l'utiliser.

Je suis sûr qu'il y a plus de raisons pour l'utiliser/ne pas utiliser que les autres post

EIT: Voir le prochain post dans ce fil pour une excellente raisonnement derrière chaque.

208voto

Phil Bennett Points 2987

Définition implicite serait de simplement ajouter les méthodes / propriétés etc exigé par l'interface directement à la classe des méthodes publiques.

Définition explicite des forces de l'méthodes pour être exposés lors de l'utilisation de l'interface directement, et non l'implémentation sous-jacente. C'est préférable dans la plupart des cas.

  1. En travaillant directement avec l'interface, vous n'êtes pas reconnaissant, et de couplage de votre code pour l'implémentation sous-jacente.
  2. Dans le cas où vous avez déjà, disons, un public Nom de la propriété dans votre code et vous souhaitez mettre en place une interface qui dispose également d'un Nom de la propriété, en faisant explicitement permettra de maintenir les deux. Même s'ils faisaient la même chose, je serais encore délégué de l'explicite appel à la propriété Name. Vous ne savez jamais, vous pourriez vouloir changer comment Nom œuvres pour la classe normale et la façon dont le Nom, l'interface la propriété des œuvres plus tard.
  3. Si vous implémenter une interface implicitement votre classe maintenant expose de nouveaux comportements qui peuvent seulement être pertinents pour un client de la interface et cela signifie que vous ne gardons pas vos classes succincte assez (à mon avis).

73voto

Matthew Scharley Points 43262

En plus des excellentes réponses déjà fournies, il y a certains cas où la mise en œuvre explicite est NÉCESSAIRE pour le compilateur pour être en mesure de comprendre ce qui est nécessaire. Jetez un oeil à l' IEnumerable<T> comme un premier exemple qui sera probablement assez souvent.

Voici un exemple:

public abstract class StringList : IEnumerable<string>
{
    private string[] _list = new string[] {"foo", "bar", "baz"};

    // ...

    #region IEnumerable<string> Members
    public IEnumerator<string> GetEnumerator()
    {
        foreach (string s in _list)
        { yield return s; }
    }
    #endregion

    #region IEnumerable Members
    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
    #endregion
}

Ici, IEnumerable<string> implémente IEnumerable, donc nous avons besoin de trop. Mais s'accrocher, à la fois génériques et de la version normale à la fois de mettre en œuvre des fonctions avec la même signature de la méthode (C# ignore le type de retour de cette dernière). C'est tout à fait légale et bien. Comment le compilateur résoudre à utiliser? Il vous oblige à, au plus, à une définition implicite, alors il est possible de résoudre ce qu'il doit.

c'est à dire.

StringList sl = new StringList();

// uses the implicit definition.
IEnumerator<string> enumerableString = sl.GetEnumerator();
// same as above, only a little more explicit.
IEnumerator<string> enumerableString2 = ((IEnumerable<string>)sl).GetEnumerator();
// returns the same as above, but via the explicit definition
IEnumerator enumerableStuff = ((IEnumerable)sl).GetEnumerator();

PS: La petite pièce d'indirection dans la définition explicite de l'interface IEnumerable fonctionne parce que l'intérieur de la fonction, le compilateur sait que le type de la variable est une StringList, et c'est la façon dont il résout l'appel de la fonction. Chouette petit fait pour la mise en œuvre de certaines des couches d'abstraction de certains de la .NET de base des interfaces semblent avoir accumulé.

37voto

Valentin Kuzub Points 4349

Pour citer Jeffrey Richter de CLR via C#

Il est extrêmement important pour vous de comprendre certaines ramifications qui lors de l'utilisation d'EIMIs. Et à cause de ces ramifications, vous devriez essayer de éviter EIMIs autant que possible. Heureusement, des interfaces génériques aider vous évitez EIMIs un peu. Mais il n'y peut-être encore des moments où vous aurez besoin de pour les utiliser (comme la mise en place de deux les méthodes d'interface avec le même nom et la signature). Ici, ce sont les grandes problèmes avec EIMIs:

  • Il n'y a pas de documentation expliquant comment un type spécifiquement
    implémente une EIMI méthode, et il y
    est pas Microsoft Visual Studio
    IntelliSense de soutien.
  • Type de la valeur des instances sont en boîte quand il est lancé à une interface.
  • Un EIMI ne peut être appelé par un type dérivé.

Généralement je vois des Interfaces Semi (au mieux) de la POO, il fournit de l'héritage, mais il ne fournit pas de véritable polymorphisme. Pour obtenir la vraie polymorphisme vous avez BESOIN de la base de référence de classe, elle garantira que les méthodes virtuelles chaînes sont correctement utilisés.

Si vous utilisez l'interface de référence virtuels, la chaîne peut être explicitement remplacé avec l'IEMI sur toute classe dérivée et où l'objet de ce type est jeté à l'interface de votre chaîne virtuelle est ignoré et la mise en œuvre explicite est appelé. C'est rien, mais le polymorphisme.

IEMIs peut également être utilisé pour masquer les non fortement typé interface les membres du Cadre de base des Interfaces des implémentations comme IEnumerable si votre classe n'expose pas non fortement typé méthode directement, mais est-syntaxique correcte.

35voto

Jon Nadal Points 394

Raison n ° 1

J'ai tendance à utiliser d'interface explicite de mise en œuvre lorsque je veux décourager "la programmation pour une mise en œuvre" (http://www.artima.com/lejava/articles/designprinciples.html).

Par exemple, dans un titre de MVP à base de web app

public interface INavigator {
    void Redirect(string url);
}

public sealed class StandardNavigator : INavigator {
    void INavigator.Redirect(string url) {
        Response.Redirect(url);
    }
}

Maintenant, une autre classe (par exemple en tant que présentateur) est moins susceptible de dépendre du StandardNavigator la mise en œuvre et plus susceptibles de dépendre de la INavigator interface (depuis la mise en œuvre devra être exprimées à une interface de rendre l'utilisation de la méthode de Redirection).

Raison n ° 2

Une autre raison, j'irai peut-être avec une interface explicite la mise en œuvre serait de garder une classe "par défaut" de l'interface plus propre. Par exemple, si je développais une ASP.NET contrôle de serveur, je pourrais avoir besoin de deux interfaces:

  1. La classe principale de l'interface, qui est utilisé par la page web des développeurs; et
  2. "Caché" de l'interface utilisée par le présentateur que je développe pour prendre le contrôle de la logique

Voici un exemple simple. C'est une zone de liste modifiable listes de clients. Dans cet exemple, la page web du développeur n'est pas intéressé dans le remplissage de la liste; au lieu de cela, ils veulent juste être en mesure de sélectionner un client par le GUID ou pour obtenir le client sélectionné est GUID. Un présentateur permettraient d'alimenter la boîte sur le premier chargement de la page, et ce présentateur est encapsulé par le contrôle.

public sealed class CustomerComboBox : ComboBox, ICustomerComboBox {
    private readonly CustomerComboBoxPresenter presenter;

    public CustomerComboBox() {
        presenter = new CustomerComboBoxPresenter(this);
    }

    protected override void OnLoad() {
        if (!Page.IsPostBack) presenter.HandleFirstLoad();
    }

    // primary interface used by web page developers
    public Guid ClientId {
        get { return new Guid(SelectedItem.Value); }
        set { SelectedItem.Value = value.ToString(); }
    }

    // "hidden" interface used by presenter
    IEnumerable<CustomerDto> ICustomerComboBox.DataSource { set; } 
}

Le présentateur remplit la source de données, et la page web du développeur n'a jamais besoin d'être conscient de son existence.

Mais Ce n'est Pas un Argent Boulet de canon

Je ne recommanderais pas toujours employant explicite des implémentations d'interface. Ce sont juste deux exemples où ils pourraient être utiles.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X