我不确定如何提出这个问题。假设我有一个类需要访问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-我是接口编程的新手,所以如果这是一个愚蠢的问题,我道歉。
答案 0 :(得分:5)
这不是一个愚蠢的问题,这是一个很好的问题。 :)
您在界面上要求的内容通常称为“duck-typing”。它目前不受支持,但C#4.0将通过新的“dynamic
”关键字支持它。
在这一点上你真的有三个选择:
您可以上到树,直到找到共同的祖先(可能是Component
)然后向下转换为您支持的类型。如果堕落失败,你可以适当地投掷或处理。
Pro:最小代码重复。
Con:您正在以编译时类型安全性来换取运行时类型的安全性。您必须为无效的强制转换添加错误检查/处理。
<强>代码:强>
public void UseThumbnail(Component c)
{
PictureBox p = c as PictureBox;
if(p != null) // do whatever
// so forth
}
您可以根据实现此功能所需的所有内容复制功能。
Pro:维护编译时类型安全性
Con:您正在复制不同类型的代码。这可能会成为一个重要的维护负担,特别是如果你处理的是两个以上类似的类。
<强>代码:强>
public void UsePictureBox(PictureBox p)
{
// Some code X
}
public void UseOtherControl(OtherControl p)
{
// Some code X
}
您可以创建特殊的接口,并为要支持的类创建子类,以公开该常用功能。
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?