C# 使用接口变量
我仍在努力更好地理解接口。我知道它们是什么,以及如何在课堂上实现它们 我不明白的是,当您创建一个属于接口类型的变量时:C# 使用接口变量,c#,C#,我仍在努力更好地理解接口。我知道它们是什么,以及如何在课堂上实现它们 我不明白的是,当您创建一个属于接口类型的变量时: IMyInterface somevariable; 你为什么要这样做?我不明白IMyInterface如何像类一样使用……例如调用方法,所以: somevariable.CallSomeMethod(); 为什么要使用IMyInterface变量来执行此操作?该接口的目的是定义多个对象之间的契约,与具体实现无关 class Test { static void Main
IMyInterface somevariable;
你为什么要这样做?我不明白IMyInterface如何像类一样使用……例如调用方法,所以:
somevariable.CallSomeMethod();
为什么要使用IMyInterface变量来执行此操作?该接口的目的是定义多个对象之间的契约,与具体实现无关
class Test
{
static void Main()
{
SampleClass sc = new SampleClass();
IControl ctrl = (IControl)sc;
ISurface srfc = (ISurface)sc;
// The following lines all call the same method.
sc.Paint();
ctrl.Paint();
srfc.Paint();
}
因此,当您有一个IntraceISomething
和一个特定的实现时,通常会使用它
class Something : ISomething
因此,当您实例化合同时,将使用varialbe接口:
ISomething myObj = new Something();
myObj.SomeFunc();
你也应该阅读
更新:
我将通过一个(现实生活中的)示例来解释为变量而不是类本身使用接口的逻辑:
我有一个通用的寄存者界面:
Interface IRepository {
void Create();
void Update();
}
我有两个不同的实现:
class RepositoryFile : interface IRepository {}
class RepositoryDB : interface IRepository {}
每个类都有完全不同的内部实现
class Test
{
static void Main()
{
SampleClass sc = new SampleClass();
IControl ctrl = (IControl)sc;
ISurface srfc = (ISurface)sc;
// The following lines all call the same method.
sc.Paint();
ctrl.Paint();
srfc.Paint();
}
现在我有了另一个对象,一个Logger,它使用一个已经实例化的存储库来编写代码。这个对象不关心存储库是如何实现的,所以他只实现:
void WriteLog(string Log, IRepository oRep);
顺便说一句,这也可以通过使用标准类继承来实现。但是使用接口和类继承之间的区别是另一个讨论
有关抽象类和接口之间区别的更详细的讨论,请参见。例如,您有两个类:
Book
和paper
。您可以阅读其中的每一个,但是这两个从一个公共超类继承是没有意义的。因此,它们都将实现IReadable
接口:
public interface IReadable
{
public void Read();
}
public interface ITransportation
{
public void TakeMeThere(string destination);
}
现在假设您正在编写一个应用程序,为用户阅读书籍和报纸。用户可以从列表中选择一本书或一份报纸,该项目将被阅读给用户
应用程序中读取给用户的方法将此书籍
或报纸
作为参数。这在代码中可能如下所示:
public static void ReadItem(IReadable item)
{
item.Read();
}
由于参数是一个IReadable
,我们知道该对象具有方法Read()
,因此我们调用它来向用户读取它。无论这是一本书
、报纸
,还是实现IReadable
的任何其他内容,都无关紧要。各个类通过实现read()
方法准确地实现了每个项的读取方式,因为不同类的读取方式很可能不同
Book
的Read()
可能如下所示:
public void Read()
{
this.Open();
this.TurnToPage(1);
while(!this.AtLastPage)
{
ReadText(this.CurrentPage.Text);
this.TurnPage();
}
this.Close();
}
报纸
的Read()
可能会有些不同:
public void Read()
{
while(!this.OnBackPage)
{
foreach(Article article in this.CurrentPage.Articles)
{
ReadText(article.Text);
}
}
}
关键是,由接口类型的变量所包含的对象保证在其上有一组特定的方法,即使对象的可能类不以任何其他方式相关。这允许您编写适用于各种类的代码,这些类具有可在其上执行的通用操作。因为:
public void ReadItemsList(List<string> items);
public void ReadItemsArray(string[] items);
public void ReadItemsList(列表项);
public void ReadItemsArray(字符串[]项);
可以变成这样:
public void ReadItems(IEnumerable<string> items);
public void ReadItems(IEnumerable items);
编辑
你可以这样想:
你必须能够做到这一点
而不是:
你必须这样
本质上,这是方法与其调用方之间的契约。您不是在创建接口的实例,而是在创建实现接口的某个对象的实例 接口的要点是,它保证实现它的任何东西都将提供其中声明的方法 现在,以您的示例为例,您可以:
MyNiftyClass : IMyInterface
{
public void CallSomeMethod()
{
//Do something nifty
}
}
MyOddClass : IMyInterface
{
public void CallSomeMethod()
{
//Do something odd
}
}
现在你有:
IMyInterface nifty = new MyNiftyClass()
IMyInterface odd = new MyOddClass()
调用CallSomeMethod方法现在可以做一些漂亮的事情,也可以做一些奇怪的事情,当您使用IMyInterface作为类型传入时,这将变得特别有用
public void ThisMethodShowsHowItWorks(IMyInterface someObject)
{
someObject.CallSomeMethod();
}
现在,根据您是使用漂亮的类还是奇怪的类调用上述方法,您会得到不同的行为
public void AnotherClass()
{
IMyInterface nifty = new MyNiftyClass()
IMyInterface odd = new MyOddClass()
// Pass in the nifty class to do something nifty
this.ThisMethodShowsHowItWorks(nifty);
// Pass in the odd class to do something odd
this.ThisMethodShowsHowItWorks(odd);
}
编辑
这解决了我认为您想要解决的问题-为什么要将变量声明为接口类型
也就是说,为什么要使用:
IMyInterface foo = new MyConcreteClass();
优先于:
MyConcreteClass foo = new MyConcreteClass();
希望很清楚为什么在声明方法签名时要使用接口,但这就留下了关于局部作用域变量的问题:
public void AMethod()
{
// Why use this?
IMyInterface foo = new MyConcreteClass();
// Why not use this?
MyConcreteClass bar = new MyConcreteClass();
}
通常没有技术上的原因来解释为什么首选接口。我通常使用界面,因为:
- 我通常注入依赖项,因此需要多态性
- 使用接口清楚地表明了我只使用接口成员的意图
public void AMethod(string input)
{
IMyInterface foo;
if (input == "nifty")
{
foo = new MyNiftyClass();
}
else
{
foo = new MyOddClass();
}
foo.CallSomeMethod();
}
这是面向对象编程的一个基本概念——多态性。()
简单的回答是,通过使用类A中的接口,您可以为类A提供
IMyInterface
的任何实现
这也是松散耦合()的一种形式——您有许多类,但它们并不明确地相互依赖——只依赖于它们提供的属性和方法集(接口)的抽象概念。这不是C#特有的,因此我建议移到其他标志。
对于你的问题,
我们选择接口的主要原因是在两个组件(可以是dll、jar或任何其他组件)之间提供协议。
请参阅下文
public class TestClass
{
static void Main()
{
IMyInterface ob1, obj2;
ob1 = getIMyInterfaceObj();
obj2 = getIMyInterfaceObj();
Console.WriteLine(ob1.CallSomeMethod());
Console.WriteLine(obj2.CallSomeMethod());
Console.ReadLine();
}
private static bool isfirstTime = true;
private static IMyInterface getIMyInterfaceObj()
{
if (isfirstTime)
{
isfirstTime = false;
return new ImplementingClass1();
}
else
{
return new ImplementingClass2();
}
}
}
public class ImplementingClass1 : IMyInterface
{
public ImplementingClass1()
{
}
#region IMyInterface Members
public bool CallSomeMethod()
{
return true;
}
#endregion
}
public class ImplementingClass2 : IMyInterface
{
public ImplementingClass2()
{
}
#region IMyInterface Members
public bool CallSomeMethod()
{
return false;
}
#endregion
}
public interface IMyInterface
{
bool CallSomeMethod();
}
在这里,main方法不知道类,但它仍然能够得到不同的类
public interface Foo {
}
public class FooFactory {
public static Foo getInstance() {
if(os == 'Windows') return new WinFoo();
else if(os == 'OS X') return new MacFoo();
else return new GenricFoo();
}
}
public IEmployee GetEmployee(string id)
{
IEmployee emp = di.GetInstance<List<IEmployee>>().Where(e => e.Id == id).FirstOrDefault();
emp?.LastAccessTimeStamp = DateTime.Now;
return emp;
}
IDepartments rep = new DepartmentsImpl();
DepartmentsImpl rep = new DepartmentsImpl();
class Test
{
static void Main()
{
SampleClass sc = new SampleClass();
IControl ctrl = (IControl)sc;
ISurface srfc = (ISurface)sc;
// The following lines all call the same method.
sc.Paint();
ctrl.Paint();
srfc.Paint();
}
interface IControl
{
void Paint();
}
interface ISurface
{
void Paint();
}
class SampleClass : IControl, ISurface
{
// Both ISurface.Paint and IControl.Paint call this method.
public void Paint()
{
Console.WriteLine("Paint method in SampleClass");
}
// Output:
// Paint method in SampleClass
// Paint method in SampleClass
// Paint method in SampleClass
public class SampleClass : IControl, ISurface
{
void IControl.Paint()
{
System.Console.WriteLine("IControl.Paint");
}
void ISurface.Paint()
{
System.Console.WriteLine("ISurface.Paint");
}
}
IControl c = new SampleClass();
ISurface s = new SampleClass();
s.Paint();