我无法理解如何使用接口以及为什么需要它们。有人可以给我看一个简单的例子吗?
答案 0 :(得分:57)
interface IFlyable
{
void Fly();
}
class Bird : IFlyable
{
public void Fly() { }
}
class Plane : IFlyable
{
public void Fly() { }
}
List<IFlyable> things = GetBirdInstancesAndPlaneInstancesMixed();
foreach(IFlyable item in things)
{
item.Fly();
}
Bird
和Plane
除了Object
之外没有共同的基类,但你可以看到我们可以在我们的程序中使用相同的接口来组合它们,因为它们具有相同的“特写“:飞。
答案 1 :(得分:31)
public interface ISpeaks
{
string Speak();
}
public class Dog : Mammal, ISpeaks
{
public string Speak() { return "Woof!"; }
}
public class Person : Mammal, ISpeaks
{
public string Speak() { return "Hi!"; }
}
//Notice Telephone has a different abstract class
public class Telephone : Appliance, ISpeaks
{
public Person P { get; set; }
public Telephone(Person p)
{
P = p;
}
public string Speak() { return P.Speak(); }
}
[Test]
public void Test_Objects_Can_Speak()
{
List<ISpeaks> thingsThatCanSpeak = new List<ISpeaks>();
//We can add anything that implements the interface to the list
thingsThatCanSpeak.Add(new Dog());
thingsThatCanSpeak.Add(new Person());
thingsThatCanSpeak.Add(new Telephone(new Person()));
foreach(var thing in thingsThatCanSpeak)
{
//We know at compile time that everything in the collection can speak
Console.WriteLine(thing.Speak());
}
}
这很有用,因为我们可以针对接口而不是实现进行编码,因为我们可以在单个类上使用多个接口,所以我们比使用Abstract类更灵活。
答案 2 :(得分:8)
Interfaces
在某种程度上类似于定义,是interface
和实现它的类之间的一种契约。
接口仅包含方法,属性,事件或索引器的签名。实现接口的类或结构必须实现接口定义中指定的接口成员。
.NET类不能使用多重继承。因此,我们依赖于接口,并且类可以实现尽可能多的接口。相反,类继承必须是单一的。例如:
public class Customer : Person, Company {
}
我所知道的任何.NET语言(C#/ VB.NET)都不允许使用此代码。
为了解决这种不足,如果我们可以这么说,我们依赖于接口。
public interface IPerson {
string Name
string Address
string StateProvince
string ZipPostalCode
string Country
long PhoneNumber
}
public interface ICompany {
string CreditTerm
string BillingAddress
string ShippingAddress
string ContactName
long ContactPhoneNumber
long FaxNumber
}
public class Customer : IPerson, ICompany {
// Properties implementations here.
}
通过这种方式,接口就像是一种多重继承的解决方法。
另一方面,接口可以用作方法的契约。假设您有一个方法将ICompany
作为输入参数。您现在可以确保在ICompany
界面中定义属性,以便在方法中执行您的工作。
public BillCompany(ICompany company) {
// Bill company here...
}
然后,您的Customer
类对应于您期望的内容,因为它实现了ICompany
接口。
让我们创建另一个类,其定义只会实现IPerson
接口。
public class Individual : IPerson {
// Interface implementation here...
}
然后,您的BillCompany()
方法无法接受Individual
类的实例,因为它没有显示公司的要求(属性等)。
简而言之,接口是通过契约将方法绑定到接受的方式的好方法,例如继承。
在使用Interface
时确实需要采取一些预防措施,对接口的更改将破坏您的代码,作为在所有实现类中实现新成员的强制规则,而类继承不会。
这有帮助吗?
答案 3 :(得分:5)
我喜欢这篇我前几天阅读的博文:http://simpleprogrammer.com/2010/11/02/back-to-basics-what-is-an-interface/
许多人,包括我自己,已经创建了与他们所代表的类具有1对1映射的接口,但这并不总是好事,该文章解释了原因。
答案 4 :(得分:5)
当您拥有一个您希望对象实现的给定合同但您并不真正关心它们如何实现它时,界面非常有用。这是一个留给课堂本身的实现细节。
因此,假设您有一个方法,即处理保存请求。它不执行实际的保存操作,它只处理请求。因此,它可能需要List<ICanSave>
,其中ICanSave
是一个接口。该列表中的对象可以是实现该接口的任何类型。它可以是混合,也可以只包含一种类型。你只关心它实现了接口。
public interface ICanSave
{
void Save();
}
在您的方法中,您可能会有类似
的简单内容public void SaveItems(List<ICanSave> items)
{
foreach (var item in items)
{
item.Save();
}
}
这些物品是如何保存的?你不在乎!这又是实现接口的类的实现细节。你只想要任何进入该方法的类都具备这种能力。
您可以拥有一个实现将数据持久保存到文件系统的接口的类。另一个可能保存到数据库。另一个可能会称之为外部服务。等等。这是由班级作者决定的。你甚至可能有一个单元测试的存根类,什么都不做。
这只是一个用例场景,还有很多其他场景,其中有几个在BCL中。 IEnumerable<T>
是一个很好的版本,它由ICollection<T>
和IList<T>
之类的内容实现,而这些内容又由Array
和List<T>
等具体类型实现。它是使您可能习惯使用的许多编程结构的接口,例如LINQ。 LINQ不关心类的实际实现*,它只是希望能够枚举它并执行适当的过滤和/或投影。
IDisposable
是另一个很好的BCL示例。你想知道一个类需要自己清理。它需要清理的具体内容是由课程实现的,但实际上IDisposable
实现{em>需要 来清理它,所以你最好将其用于一个using
语句,或者您手动确保在完成对象处理后调用.Dispose
。
* LINQ实际上对某些接口进行了优化。
答案 5 :(得分:3)
简单的接口示例动物有两个类动物的实现(你有一个独特的动物描述和许多类狗的实现,猫......)
public interface IAnimal
{
string GetDescription();
}
class Cat : IAnimal
{
public string GetDescription()
{
return "I'm a cat";
}
}
class Program
{
static void Main(string[] args)
{
Cat myCat = new Cat();
Console.WriteLine(myCat.GetDescription());
}
}
答案 6 :(得分:1)
“我在这里有一堆课程,我希望以同样的方式对待一定数量的功能。”
所以,你写了一份合同。
真实世界的例子:我正在写一个向导。它有一堆页面,其中一些(但不是全部)是UserControls。它们都需要一组共同的操作,因此控制类可以对它们进行相同的处理。所以我有一个他们都实现的IPage接口,具有初始化页面,保存用户选择等操作。在我的控制器中,我只是有一个List,而不必知道哪个页面做了什么;我只需调用界面的Save()和Initialize()s。
答案 7 :(得分:1)
以下是Interface的要点,
1.我们可以使用相同方法的不同输出使用不同的类来调用相同的方法。
简单示例:
class Mango : abc
{
public static void Main()
{
System.Console.WriteLine("Hello Interfaces");
Mango refDemo = new Mango();
refDemo.mymethod();
Orange refSample = new Orange();
refSample.mymethod();
}
public void mymethod()
{
System.Console.WriteLine("In Mango : mymethod");
}
}
interface abc
{
void mymethod();
}
class Orange : abc
{
public void mymethod()
{
System.Console.WriteLine("In Orange : mymethod");
}
}
2.可以使用不同类的相同接口调用相同的方法。
class Mango : abc
{
public static void Main()
{
System.Console.WriteLine("Hello Interfaces");
abc refabc = new Mango();
refabc.mymethod();
abc refabd = new Orange();
refabd.mymethod();
Console.ReadLine();
}
public void mymethod()
{
System.Console.WriteLine("In Mango : mymethod");
}
}
interface abc
{
void mymethod();
}
class Orange : abc
{
public void mymethod()
{
System.Console.WriteLine("In Orange : mymethod");
}
}
答案 8 :(得分:0)
从MSDN开始,“一个接口定义了一个契约。实现接口的类或结构必须遵守它的契约。”
在this page上,有几个示例说明接口是什么样的,类是如何从接口继承的,以及如何实现接口的完整示例。
希望这会有所帮助。