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();
}
因此,当您有一个Intrace
ISomething
和一个特定的实现时,通常会使用它

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();
}
通常没有技术上的原因来解释为什么首选接口。我通常使用界面,因为:

  • 我通常注入依赖项,因此需要多态性
  • 使用接口清楚地表明了我只使用接口成员的意图
在技术上需要接口的地方是利用多态性的地方,例如使用工厂创建变量或(如我上面所说)使用依赖注入

借用itowlson的一个例子,使用具体声明,您无法做到这一点:

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();