我在c#中发现了一个行为,我想知道它是否在规范中(并且可以预期在所有平台和.NET运行时的新版本上工作),或者如果它是未定义的行为,恰好发生在工作但可能随时停止编译。
所以,假设我想采用现有的类,比如:
public class HtmlTextBox
{
public string Text {get; set;}
}
public class HtmlDiv
{
public string Text {get; set;}
}
现在我真的希望他们实现一个通用的IText接口,如下所示:
public interface IText
{
string Text {get; }
}
但我无法直接更改类,因为它们是外部库的一部分。现在有各种方法可以通过继承或装饰器来实现。 但我很惊讶地发现,简单地编译它就可以在.NET 4.5(Windows 7 64位)上运行。
public class HtmlTextBox2 : HtmlTextBox, IText {}
public class HtmlDiv2 : HtmlDiv, IText {}
就是这样。这使我可以使用HtmlTextBox
和HtmlDiv
作为Text
实现的IText
和Text
替代品。
我一半期待编译器对我大喊大叫,要求我提供IText h2 = new HtmlTextBox2{Text="Hello World"};
Console.WriteLine(h2.Text); //OUTPUT: hello world
的明确重新实现,但是在.NET 4.5上这只是有用的:
{{1}}
事实上,我在单声道(无论ideone.com使用的是什么版本)和mono does not yell at me either
上都尝试了相同的功能。所以我想我很高兴,但在尝试使用严肃的代码之前,我想检查一下我是否误解了这里发生了什么,或者我是否不能依赖它来工作。
答案 0 :(得分:9)
是的,这是预期的行为。接口方法的实现不需要在实际应用接口的类中完成;它可以在任何祖先类中。
C# Language Specification 5.0在第13.4.4节中记录了这一点;规则的摘录:
特定接口成员
I.M
的实现,其中I
是声明成员M
的接口,通过检查每个类或结构S
来确定,从C
开始,并为每个连续的C
基类重复,直到找到匹配项
答案 1 :(得分:2)
对我的评论做了一些澄清
是的,那确实应该按预期工作。接口定义了类应该实现的方法(直接或贯穿整个层次结构)。
定义界面时,可以这样看:
接口的唯一任务是保证在签名中定义接口的类层次结构中的任何一点,该类都实现了接口中的每个方法。
这是一个样本情况,希望能够解释一下:
void Main()
{
Z obj1 = new C();
Z obj2 = new B();
Z obj3 = new A();
Y obj4 = new C();
Y obj5 = new D();
Z obj6 = new D();
}
interface Y {
void someMethod1();
void someMethod2();
}
interface Z {
void someMethod3();
}
class A : Z {
public void someMethod3() { }
}
class B : A {
public void someMethod1() { }
}
class C : B, Y {
public void someMethod2() { }
}
class D : C { }
这个编译得很好。
如您所见,B
实施Y
的方法someMethod1
,之后C
扩展B
并实施Y
。所有C
都为someMethod2
提供了一个实现,此时达到了接口定义:Y
中定义的两个方法现在可用于{{1}类型的对象}}
这里的关键是要记住,类层次结构只是层,其中包括一些方法。在层次结构中,当您说“此类需要实现C
中定义的每个方法”时,您基本上必须确保在此时您的每个方法都可用。继承告诉我们,我们可以使用超类的方法,这意味着通过在基类中实现您的方法,您已满足条件。
旁注:所有这些都是在没有<SomeInterface>
方法的情况下编写的,它们有点不同。