例如,假设我想要一个ICar接口,并且所有实现都将包含字段Year。这是否意味着每个实现都必须单独声明Year?在接口中简单地定义它不是更好吗?


当前回答

其他人已经给出了“为什么”,所以我只是补充说,你的界面可以定义一个控件;如果你把它包装在属性中:

public interface IView {
    Control Year { get; }
}


public Form : IView {
    public Control Year { get { return uxYear; } } //numeric text box or whatever
}

其他回答

从c# 8.0开始,接口可以为成员定义默认实现,包括属性。很少在接口中为属性定义默认实现,因为接口可能不定义实例数据字段。

https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/interface-properties

interface IEmployee
{
    string Name
    {
        get;
        set;
    }

    int Counter
    {
        get;
    }
}

public class Employee : IEmployee
{
    public static int numberOfEmployees;

    private string _name;
    public string Name  // read-write instance property
    {
        get => _name;
        set => _name = value;
    }

    private int _counter;
    public int Counter  // read-only instance property
    {
        get => _counter;
    }

    // constructor
    public Employee() => _counter = ++numberOfEmployees;
}

将其声明为属性:

interface ICar {
   int Year { get; set; }
}

为什么不使用Year属性呢?

接口不包含字段,因为字段表示数据表示的特定实现,暴露它们会破坏封装。因此,拥有一个带有字段的接口将有效地编码到一个实现,而不是一个接口,这是一个奇怪的接口!

例如,部分Year规范可能要求ICar实现者允许赋值给比当前年份+ 1晚或1900年之前的年份是无效的。如果您已经公开Year字段,就无法这样说——在这里使用属性来完成工作要好得多。

接口定义了公共实例属性和方法。字段通常是私有的,或者至多是受保护的、内部的或受保护的内部的(术语“字段”通常不用于任何公共的内容)。

正如其他回复所述,您可以定义一个基类并定义一个受保护的属性,该属性将被所有继承者访问。

一个奇怪的地方是,一个接口实际上可以被定义为内部的,但它限制了接口的有用性,并且它通常用于定义其他外部代码不使用的内部功能。

简短的回答是肯定的,每个实现类型都必须创建自己的支持变量。这是因为接口类似于契约。它所能做的就是指定实现类型必须提供的特定的公开可访问的代码段;它本身不能包含任何代码。

用你的建议来考虑这个场景:

public interface InterfaceOne
{
    int myBackingVariable;

    int MyProperty { get { return myBackingVariable; } }
}

public interface InterfaceTwo
{
    int myBackingVariable;

    int MyProperty { get { return myBackingVariable; } }
}

public class MyClass : InterfaceOne, InterfaceTwo { }

这里有几个问题:

因为接口的所有成员(根据定义)都是公共的,所以我们的备份变量现在暴露给使用该接口的任何人 MyClass将使用哪个myBackingVariable ?

最常用的方法是声明接口和实现它的基本抽象类。这使得您可以灵活地从抽象类继承并免费获得实现,或者显式地实现接口并允许从另一个类继承。它是这样工作的:

public interface IMyInterface
{
    int MyProperty { get; set; }
}

public abstract class MyInterfaceBase : IMyInterface
{
    int myProperty;

    public int MyProperty
    {
        get { return myProperty; }
        set { myProperty = value; }
    }
}