Question

Dans Programming C # (p.142) de Jesse Liberty, il donne un exemple dans lequel il convertit un objet sur une interface.

 interface IStorable
 {
    ...
 }

 public class Document : IStorable
 {
    ...
 }

 ...
 IStorable isDoc = (IStorable) doc;  
 ...

Quel est l'intérêt de ceci, en particulier si la classe de l'objet implémente quand même l'interface?

EDIT1: Pour clarifier, je suis intéressé par la raison de la diffusion (le cas échéant) , pas la raison de la mise en œuvre des interfaces. En outre, le livre est sa première édition de 2001 (basé sur C # 1, donc cet exemple pourrait ne pas être pertinent pour les versions ultérieures de C #).

EDIT2: j'ai ajouté du contexte au code

Était-ce utile?

La solution

Il existe une seule raison pour laquelle vous avez réellement besoin d'un transtypage: lorsque doc est du type de base d'un objet qui implémente IStorable. Laissez-moi vous expliquer:

public class DocBase
{
  public virtual void DoSomething()
  {

  }
}

public class Document : DocBase, IStorable
{
  public override void DoSomething()
  {
    // Some implementation
    base.DoSomething();
  }

  #region IStorable Members

  public void Store()
  {
    // Implement this one aswell..
    throw new NotImplementedException();
  }

  #endregion
}

public class Program
{
  static void Main()
  {
    DocBase doc = new Document();
    // Now you will need a cast to reach IStorable members
    IStorable storable = (IStorable)doc;
  }
}

public interface IStorable
{
  void Store();
}

Autres conseils

Parce que vous souhaitez vous limiter aux méthodes fournies par l'interface. Si vous utilisez la classe, vous courez le risque d’appeler (par inadvertance) une méthode qui ne fait pas partie de l’interface.

Si l'objet implémente l'interface explicitement ( public void IStorable.StoreThis (...) ), cette diffusion est le moyen le plus simple pour atteindre les membres de l'interface.

Je ne sais pas dans quel contexte l'exemple a été donné dans le livre. Cependant, vous pouvez généralement transtyper un objet en interface pour obtenir un héritage multiple. J'ai donné l'exemple ci-dessous.

public interface IFoo
{
     void Display();
}
public interface IBar
{
     void Display();
}

public class MyClass : IFoo, IBar
{
    void IBar.Display()
    {
        Console.WriteLine("IBar implementation");
    }
    void IFoo.Display()
    {
        Console.WriteLine("IFoo implementation");
    }
}

public static void Main()
{
    MyClass c = new MyClass();
    IBar b = c as IBar;
    IFoo f = c as IFoo;
    b.Display();
    f.Display();
    Console.ReadLine();
}

Ceci afficherait

  

Implémentation IBar
  Implémentation IFoo

C'est assez difficile à dire sans plus de contexte. Si la variable doc est déclarée comme un type qui implémente l'interface, la conversion est redondante.

Quelle version du livre lisez-vous? Si c'est "Programmer en C # 3.0" Je vais regarder ce soir quand je suis à la maison.

EDIT: Comme nous l’avons vu dans les réponses jusqu’à présent, il existe trois questions potentielles:

  • Pourquoi utiliser l'affirmation indiquée dans la question? (Réponse: vous n'êtes pas obligé si doc est d'un type de compilation approprié)
  • Pourquoi est-il toujours approprié de convertir explicitement une interface ou une classe de base implémentée? (Réponse: implémentation d'interface explicite, comme indiqué dans une autre réponse, et également dans le but de choisir une surcharge moins spécifique lors du passage de la valeur de la distribution en tant qu'argument.)
  • Pourquoi utiliser l'interface du tout? (Réponse: travailler avec le type d'interface signifie que vous serez moins susceptible de changer ultérieurement de type concret.)

L'objet doc peut être d'un type implémentant explicitement les membres de IStorable , sans les ajouter à l'interface primaire de la classe (c'est-à-dire qu'ils peuvent uniquement être appelés via interface).

En fait, "casting" " (en utilisant la syntaxe (T)) n’a aucun sens puisque C # gère automatiquement les diffusions ultérieures (converties en type parent) (contrairement à F #, par exemple).

Il y a beaucoup de bonnes réponses ici, mais je ne pense pas vraiment qu'elles répondent POURQUOI vous VOULEZ réellement utiliser l'interface la plus restrictive possible.

Les raisons n'impliquent pas votre codage initial, mais la prochaine fois que vous visitez ou modifiez le code - ou que quelqu'un d'autre le fait.

Supposons que vous souhaitiez un bouton et le placiez sur votre écran. Vous obtenez le bouton transmis ou provenant d’une autre fonction, comme ceci:

Button x=otherObject.getVisibleThingy();
frame.add(x);

Vous savez que VisibleThingy est un bouton, il renvoie un bouton, donc tout est cool ici (aucun casting requis).

Maintenant, disons que vous refactorisez VisibleThingy pour renvoyer un bouton bascule à la place. Vous devez maintenant revoir votre méthode car vous en saviez trop sur la mise en œuvre.

Puisque vous N'AVEZ BESOIN que des méthodes dans Component (parent du bouton et de Toggle, qui aurait pu être une interface - même chose pour nos besoins), si vous aviez écrit cette première ligne comme ceci:

Component x=(Component)otherObject.getVisibleThingy();

Vous n’auriez pas eu à refacturer quoi que ce soit, cela aurait simplement fonctionné.

Ceci est un cas très simple, mais il peut être beaucoup plus complexe.

Donc, je suppose que le résumé serait qu'une interface est un moyen spécifique de " Afficher " votre objet - comme regarder à travers un filtre ... vous ne pouvez voir que certaines parties. Si vous pouvez restreindre suffisamment votre affichage, l’objet peut "Morph". derrière votre point de vue particulier et n’affectez en rien votre monde actuel - une astuce très puissante de l’abstraction.

Si vous écrivez du code contre des objets sans connaître leur type concret et que vous ne le souhaitez pas, la meilleure raison pour laquelle vous utiliserez des interfaces est d'interface utilisateur.

Si vous savez que vous pouvez rencontrer un objet implémentant une interface spécifique, vous pouvez alors extraire les valeurs de l'objet sans avoir à connaître la classe concrète de cet objet. De même, si vous savez qu'un objet implémente une interface donnée, cette dernière peut définir des méthodes que vous pouvez exécuter pour effectuer certaines actions sur l'objet.

Voici un exemple simple:

public interface IText
{
   string Text { get; }
}

public interface ISuperDooper
{
   string WhyAmISuperDooper { get; }
}

public class Control
{
   public int ID { get; set; }
}

public class TextControl : Control, IText
{
   public string Text { get; set; }
}

public class AnotherTextControl : Control, IText
{
   public string Text { get; set; }
}

public class SuperDooperControl : Control, ISuperDooper
{
   public string WhyAmISuperDooper { get; set; }
}

public class TestProgram
{
   static void Main(string[] args)
   {
      List<Control> controls = new List<Control>
               {
                   new TextControl
                       {
                           ID = 1, 
                           Text = "I'm a text control"
                       },
                   new AnotherTextControl
                       {
                           ID = 2, 
                           Text = "I'm another text control"
                       },
                   new SuperDooperControl
                       {
                           ID = 3, 
                           WhyAmISuperDooper = "Just Because"
                       }
               };

       DoSomething(controls);
   }

   static void DoSomething(List<Control> controls)
   {
      foreach(Control control in controls)
      {
         // write out the ID of the control
         Console.WriteLine("ID: {0}", control.ID);

         // if this control is a Text control, get the text value from it.
         if (control is IText)
            Console.WriteLine("Text: {0}", ((IText)control).Text);

         // if this control is a SuperDooperControl control, get why
         if (control is ISuperDooper)
            Console.WriteLine("Text: {0}", 
                ((ISuperDooper)control).WhyAmISuperDooper);
      }
   }
}

exécuter ce petit programme vous donnerait la sortie suivante:

  

ID: 1

     

Texte: je suis un contrôle de texte

     

ID: 2

     

Texte: je suis un autre contrôle de texte

     

ID: 3

     

Texte: juste parce que

Notez que je n'ai pas eu à écrire de code dans la méthode DoSomething qui m'a obligé à connaître quoi que ce soit à propos de tous les objets sur lesquels je travaillais, étant des types d'objet concrets. La seule chose que je sache, c'est que je travaille sur des objets qui sont au moins une instance de la classe Control. Je peux ensuite utiliser l'interface pour savoir ce qu'ils peuvent encore avoir.

Il existe un million de raisons différentes pour lesquelles vous adopteriez cette approche avec des interfaces sur vos objets, mais cela vous donne un moyen lâche d'accéder à vos objets sans avoir à savoir exactement ce que c'est.

Pensez à toutes les cartes de crédit du monde, chaque entreprise fabrique la leur, l'interface est la même, cependant, chaque lecteur de carte peut faire passer une carte conforme à la norme. Similaire à l'utilisation d'interfaces.

Comme cela a été noté, la coulée est superflue et non nécessaire. Cependant, il s'agit d'une forme de codage plus explicite qui serait utile aux débutants pour les aider à mieux comprendre.

Dans un manuel d'introduction, il est préférable d'agir explicitement plutôt que de laisser le complileur faire les choses implicitement, ce qui serait plus déroutant pour les débutants.

Le " doc " n'est pas du type " IStorable " il serait donc déroutant pour les débutants de voir qu’il est assigné à un isDoc. En explicitant le casting, l'auteur (du livre et du code) dit qu'un document peut être converti en un objet IStorable, mais ce n'est pas la même chose qu'un objet IStorable.

Le fait est que l'objet (où l'avez-vous obtenu?) ne peut pas implémenter l'interface, auquel cas une exception est générée qui peut être interceptée et traitée. Bien sûr, vous pouvez utiliser le " is " opérateur à vérifier, et le "en tant que" opérateur pour lancer au lieu de la distribution de style C.

Pour permettre le plus grand nombre possible de découplages entre les éléments de code ...

Voir l'article suivant pour plus d'informations: Interfaces

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top