在控件之间连接常见功能

时间:2009-04-30 18:05:34

标签: c# interface

我不确定如何提出这个问题。假设我有一个类需要访问Control的某些属性(例如,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。

Thx,Sam

PS-我是接口编程的新手,所以如果这是一个愚蠢的问题,我道歉。

7 个答案:

答案 0 :(得分:5)

这不是一个愚蠢的问题,这是一个很好的问题。 :)

您在界面上要求的内容通常称为“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 
    { }
    

答案 1 :(得分:2)

我想你必须让自己的类派生自PictureBox。这个新课程也将实现IThumbnail。

public class MyPictureBox : PictureBox, IThumbnail {

}

答案 2 :(得分:2)

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...
}

答案 3 :(得分:1)

您可以创建自己的类来实现接口,并在幕后拥有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”,此模式也很有用,在这种情况下,您不会从中扩展它。

实际上,Derik Whittaker在dimecasts.net here

上做了一个关于这种模式的精彩播客

答案 4 :(得分:1)

如果您对创建接口感兴趣的类没有“密封”,那么您可以创建一个新类并从非密封类继承,实现该接口。

如果 密封(我认为PictureBox不是),你可能想要构建一个包装类来实现你感兴趣的接口并包含一个PictureBox控件,只展示您感兴趣的成员。

答案 5 :(得分:0)

.net运行时中有数百个接口。如果接口是隐式实现的,并且编译器要经过并自动将接口与类匹配,那么您编写的每个类都可以匹配到您甚至不想要它的接口。

正如其他海报所暗示的那样,你的情况正是OO要解决的问题;) 尝试扩展PictureBox以实现您的界面。

答案 6 :(得分:0)

您所描述的情况正是接口的用途

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的特定部分。

修改

这个问题涉及同一个问题 Will C#4.0 allow dynamic casting, If not, should it?