Pergunta

O No Jesse Liberty programação C # (p.142), ele fornece um exemplo onde ele lança um objeto para uma interface.

 interface IStorable
 {
    ...
 }

 public class Document : IStorable
 {
    ...
 }

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

O que é o ponto deste, particularmente se implementos classe do objeto do Inteface afinal?

EDIT1: Para esclarecer, eu estou interessado no razão para o elenco (se houver) , não a razão para a implementação de interfaces. Além disso, o livro é o seu 2001 Primeira Edição (baseado em C # 1 para que o exemplo pode não ser pertinente para versões posteriores do C #).

EDIT2: Eu adicionei um pouco de contexto para o código

Foi útil?

Solução

Há apenas uma razão, quando você realmente precisa de um elenco: Quando doc é de um tipo de base de um objeto real que implementos IStorable. Deixe-me explicar:

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

Outras dicas

Porque você quer restringir-se a apenas métodos fornecidos pela interface. Se você usar a classe, você corre o risco de chamar um método (inadvertidamente) que não faz parte da interface.

Se os implementos objeto a interface explicitamente (public void IStorable.StoreThis(...)) que casting é a maneira mais fácil para realmente alcançar os membros de interface.

Eu não estou certo em que contexto, o exemplo foi dado no livro. Mas, geralmente você pode digitar converter um objeto para interface para conseguir a herança múltipla. Eu dei o exemplo abaixo.

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

Este seria exibido

implementação IBar
implementação IFoo

É muito difícil dizer, sem mais do contexto. Se o doc variável é declarada para ser um tipo que implementa a interface, em seguida, o elenco é redundante.

Versão Qual o livro que você está lendo? Se é "Programação C # 3.0" Vou ter um olhar esta noite, quando estou em casa.

EDIT: Como vimos nas respostas até agora, há três questões potenciais aqui:

  • Por que lançar na demonstração mostrado na pergunta? (Resposta: você não tem que se doc é de um tipo de tempo de compilação apropriado)
  • Por que é que nunca se apropriar de lançar explicitamente uma interface implementada ou classe base? (Resposta:. Implementação de interface explícita, como mostrado em outra resposta, e também por uma questão de escolher uma sobrecarga menos específico ao passar o valor elenco como um argumento)
  • Por que usar a interface em tudo? (Resposta:. Trabalhando com os meios tipo de interface que você está menos suscetível a mudanças no tipo de concreto mais tarde)

O objeto doc pode ser de um tipo que implementa membros da IStorable explicitamente, não adicioná-los às classes interface primária (ou seja, eles só pode ser chamado através da interface).

Na verdade, "lançando" (usando a sintaxe (T)) não faz qualquer sentido, uma vez C # alças upcasts (CAST para tipo pai) automaticamente (ao contrário F # por exemplo).

Há um monte de boas respostas aqui, mas eu realmente não acho que eles responder por que você realmente quer usar a interface mais restritivo possível.

As razões não envolvem sua inicial de codificação, que envolvem a próxima vez que você visitar ou refatorar o código -. Ou quando alguém faz isso

Vamos dizer que você quer um botão e está colocando-o em sua tela. Você está recebendo o botão seja aprovada em ou a partir de outra função, como este:

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

Você por acaso sabe que VisibleThingy é um botão, ele retorna um botão, então tudo é fresco aqui (sem elenco necessário).

Agora, vamos dizer que você refatorar VisibleThingy para retornar um botão de alternância vez. agora você tem que refazer o seu método, porque você sabia demais sobre a implementação.

Uma vez que você só precisa de métodos no componente (um pai de tanto botão e alavanca, o que poderia ter sido uma interface - mesma coisa praticamente para os nossos propósitos), se você tivesse escrito que a primeira linha como esta:

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

Você não teria tido a refatorar nada -. Que teria apenas trabalhou

Este é um caso muito simples, mas pode ser muito mais complexa.

Então eu acho que o resumo seria que uma interface é uma maneira específica de "View" o seu objeto - como olhar para ele através de um filtro ... você pode ver apenas algumas partes. Se você pode restringir sua visão suficiente, o objeto pode "Morph" atrás de sua visão particular e não efeito qualquer coisa em seu mundo atual -. Um poderoso truque de abstração

A melhor razão por que você iria lançar a interfaces seria se você estiver escrevendo código contra objetos e você não sabe que tipo de concreto que são e que você não quer.

Se você sabe que você pode se deparar com um objeto que implementa uma específica interface que você poderia, então, obter os valores para fora do objeto sem ter que saber a classe concreta que esse objeto é. Além disso, se você sabe que um objeto implementa uma determinada interface, essa interface pode definir métodos que você pode executar a tomar certas ações sobre o objeto.

Aqui está um exemplo simples:

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

executar este programa pouco lhe daria o seguinte resultado:

ID: 1

Texto: Eu sou um controle de texto

ID: 2

Texto: Eu sou um outro controle de texto

ID: 3

Texto: Just Because

Observe que eu não tenho que escrever qualquer código no método DoSomething que me obrigado a saber nada sobre todos os objetos que eu estava trabalhando em ser tipos de objeto concreto. A única coisa que eu sei é que eu estou trabalhando em objetos que são, pelo menos, uma instância da classe Control. Posso, então, usar a interface para descobrir o que mais eles poderiam ter.

Há um milhão de razões diferentes que você tomaria esta abordagem com interfaces em seus objetos, mas dá-lhe uma maneira solta para acessar seus objetos sem ter que saber exatamente o que é.

Pense em todos os cartões de crédito do mundo, cada empresa faz a sua própria, a interface é a mesma, porém, assim que cada leitor de cartão pode ter um cartão fraudado através dele que segue o padrão. Similar ao uso de interfaces.

Como foi observado, o elenco é supérfluo e não é necessário. No entanto, é uma forma mais explícita de codificação que seria útil para iniciantes em ajudar a sua compreensão.

Em um livro introdutório, é melhor agir de forma explícita, em vez de deixar o compliler fazer as coisas de forma implícita, o que seria mais confuso para iniciantes.

O "doc" não é do tipo "IStorable" para que ele iria ser confuso para iniciantes para ver que ele está sendo atribuído a um isDoc. Ao lançar explicitamente, o autor (do livro e do código) está dizendo que um documento pode ser fundido a um objeto IStorable, mas não é o mesmo como um objeto IStorable.

O ponto é, o objeto (de onde você tirou isso?) Pode não implementar a interface, caso em que uma exceção é lançada, que podem ser capturados e tratados. Claro que você pode usar o "é" operador verificar, eo "como" operador elenco vez do elenco de estilo C.

Para permitir a maior dissociação entre pedaços de código ...

Consulte o seguinte artigo para mais: Interfaces

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top