Взаимодействие общих функций между элементами управления - PullRequest
1 голос
/ 30 апреля 2009

Я не совсем уверен, как задать этот вопрос. Предположим, у меня есть класс, которому требуется доступ к определенным свойствам элемента управления (например, Visible и Location). Возможно, я хочу использовать тот же класс для доступа к свойствам другого элемента с таким же именем, но класс может не быть производным от Control. Поэтому я попытался сделать интерфейс:

public interface IThumbnail {

    bool    Visible     { get; set; }
    int     Height      { get; set; }
    int     Width       { get; set; }
    Image   Image       { get; set; }
    Point   Location    { get; set; }

    event EventHandler Click;
}

Обратите внимание, что, например, PictureBox реализует этот интерфейс. Однако, поскольку определение класса не говорит , что оно реализует IThumbnail, я не могу привести PictureBoxes к IThumbnails - я получаю InvalidCastException во время выполнения. Но почему CLR не может «выяснить», что PictureBox действительно реализует IThumbnail (он просто не говорит об этом прямо).

Кроме того, что я должен сделать, чтобы справиться с этой ситуацией? Я хочу получить доступ к некоторым свойствам PictureBox, не сообщая моему классу, что он изменяет PictureBox.

Спасибо, Сэм

PS- Я новичок в программировании интерфейса, поэтому я прошу прощения, если это глупо q.

Ответы [ 7 ]

5 голосов
/ 30 апреля 2009

Это не глупый вопрос, это хороший. :)

То, что вы запрашиваете в интерфейсе, обычно называется " duck-typing ". Сейчас это не поддерживается, но C # 4.0 будет поддерживать его с помощью нового ключевого слова "dynamic".

У вас действительно есть три варианта, о которых я знаю на данный момент:

  1. Вы можете подниматься по дереву, пока не найдете общего предка (вероятно, Component), а затем перейти к поддерживаемым типам. Если сбой удался, вы бросаете или обрабатываете соответственно.

    Pro: Минимальное дублирование кода.

    Con: Вы тратите деньги на безопасность во время компиляции для безопасности во время выполнения. Вы должны добавить проверку / обработку ошибок для неверных приведений.

    Код:

    public void UseThumbnail(Component c) 
    {
        PictureBox p = c as PictureBox;
        if(p != null) // do whatever
        // so forth
    }
    
  2. Вы можете дублировать функциональность в зависимости от того, для чего вам нужно реализовать эту функцию.

    Pro: Сохранение безопасности типа времени компиляции

    Con: Вы дублируете код для разных типов. Это может привести к значительному бремени обслуживания, особенно если вы работаете с более чем двумя аналогичными классами.

    Код:

    public void UsePictureBox(PictureBox p)
    {
        // Some code X
    }
    
    public void UseOtherControl(OtherControl p)
    {
        // Some code X
    }
    
  3. Вы можете создать свой специальный интерфейс и создать подкласс для классов, которые вы хотите поддерживать, для предоставления этой общей функциональности.

    Pro: Вы получаете безопасность во время компиляции и можете программировать на новый интерфейс.

    Con: Вам нужно добавить пустой подкласс для всего, с чем вы имеете дело, и вам нужно использовать их.

    Код:

    public class ThumbnailPictureBox : PictureBox, IThumbnail 
    { }
    
2 голосов
/ 30 апреля 2009

CLR не может понять, что PictureBox реализует ту же сигнатуру метода, что и IThumbnail, потому что она просто еще не поддерживается. Функцию, о которой вы здесь говорите, часто называют Duck Typing , и это особенность динамических языков, таких как Ruby - она ​​должна быть доступна в .NET и C # со следующим выпуском (C # 4) и DLR (динамический язык исполнения).

Чтобы получить необходимую вам функциональность прямо сейчас, вы можете написать класс, который реализует интерфейс IThumbnail и инкапсулирует экземпляр PictureBox.

public class ThumbnailPictureBox
{
  private PictureBox _pictureBox;

  public ThumbnailPictureBox(PictureBox pictureBox)
  {
    _pictureBox = pictureBox;
  }

  public bool Visible
  {
    get { return _pictureBox.Visible; }
    set { _pictureBox.Visible = value; }
  }

 // etc...
}
2 голосов
/ 30 апреля 2009

Полагаю, вам нужно создать собственный класс, производный от PictureBox. Этот новый класс также будет реализовывать IThumbnail.

public class MyPictureBox : PictureBox, IThumbnail {

}
1 голос
/ 30 апреля 2009

Если класс, для которого вы хотите создать интерфейс, не является «запечатанным», то вы можете создать новый класс и наследовать от незапечатанного класса, реализуя интерфейс.

Если бы было запечатано (и я не думаю, что PictureBox это), вы, вероятно, захотите создать класс-оболочку, реализующий интересующий вас интерфейс и содержащий элемент управления PictureBox, предоставляя только те участники, которые вас интересуют.

1 голос
/ 30 апреля 2009

Вы можете создать свой собственный класс, который реализует интерфейс и имеет за кадром PictureBox

class MyPictureBox: IThumbnail
{
    private PictureBox _pictureBox = new PictureBox();

    bool Visible     
    { 
        get 
        { 
            return _pictureBox.Visible; 
        } 
        set 
        { 
            _pictureBox.Visible = value; 
        }
    }

    //implement the rest, you get the idea
}

Этот шаблон также будет полезен в том случае, если вы хотите расширить "PictureBox" стороннего производителя, который запечатан, и в этом случае вы не сможете расширять его.

На самом деле Дерик Уиттакер только что сделал хороший подкаст по этому шаблону на dimecasts.net здесь

0 голосов
/ 30 апреля 2009

Ситуация, которую вы описываете, является именно тем, для чего предназначены интерфейсы

public interface IThumbnail
{
   bool Visible {get; set;}
   string FilePath {get; set;}
}

public class Bar : IFoo
{
   bool Visible {get; set;}
   int SomeNumber {get; set;}
   /* 
     rest of Bar functionality
   */
}

public class SomeClass
{
   public void DisplayThumbnail(IThumbnail thumb)
   {
      //Do Stuff to things.
   }
}

Как только это реализовано таким образом, для любого аспекта вашей программы, который не должен иметь доступа к каким-либо функциям Bar, но ДОЛЖЕН иметь доступ к любым функциям IThumbnail, просто передайте им объект типа IThumbnail

Bar bar = new Bar();

SomeClass someClass = new SomeClass();

someClass.DisplaySomething((IThumbnail) bar);

Теперь функция DisplaySomething не может получить доступ к каким-либо исключительным функциям Bar. Он может получить доступ только к IThumbnail его частям.

EDIT

Этот вопрос касается той же проблемы Будет ли C # 4.0 разрешать dynamic кастинг, если нет, не так ли?

0 голосов
/ 30 апреля 2009

В среде выполнения .net сотни интерфейсов. Если интерфейсы оставлены для неявной реализации, и компилятор должен был пройти и автоматически сопоставить интерфейсы с классами, каждый класс, который вы программируете, мог бы быть сопоставлен с интерфейсами, которые вы даже не хотели.

Как и предполагали другие авторы, ваша ситуация - именно то, для чего предназначен ОО;) Попробуйте расширить PictureBox для реализации вашего интерфейса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...