Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/wix/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么可以';tc#接口是否包含字段?_C#_Interface - Fatal编程技术网

为什么可以';tc#接口是否包含字段?

为什么可以';tc#接口是否包含字段?,c#,interface,C#,Interface,例如,假设我需要一个ICar接口,并且所有实现都将包含Year字段。这是否意味着每个实现都必须单独声明年份?在接口中简单地定义它不是更好吗?将其声明为属性: interface ICar { int Year { get; set; } } class Automobile : ICar { public int Year { get; set; } // automatically implemented } public interface IView { Cont

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

将其声明为属性:

interface ICar {
   int Year { get; set; }
}
class Automobile : ICar
{
    public int Year { get; set; } // automatically implemented
}
public interface IView {
    Control Year { get; }
}


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

为什么不干脆拥有一个
Year
房产,这很好

接口不包含字段,因为字段表示数据表示的特定实现,而公开这些字段将破坏封装。因此,拥有一个带有字段的接口将实际上是编码到一个实现而不是一个接口,这对于一个接口来说是一个奇怪的悖论


例如,
Year
规范的一部分可能要求
ICar
实施者允许分配到晚于当前年份+1或1900年之前的
Year
是无效的。没有办法说,如果您已经公开了
Year
字段,那么最好使用属性来完成这里的工作。

为此,您可以有一个实现Year字段的Car基类,而所有其他实现都可以从中继承。

C#中的接口旨在定义类将遵守的契约,而不是特定的实现。

本着这种精神,C#接口确实允许定义属性——调用者必须为其提供实现:

interface ICar
{
    int Year { get; set; }
}
如果没有与属性关联的特殊逻辑,则实现类可以使用自动属性简化实现:

interface ICar {
   int Year { get; set; }
}
class Automobile : ICar
{
    public int Year { get; set; } // automatically implemented
}
public interface IView {
    Control Year { get; }
}


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

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

使用您的建议考虑此场景:

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; }
    }
}

接口不包含任何实现

  • 定义具有属性的接口
  • 此外,您可以在任何类中实现该接口,并继续使用该类
  • 如果需要,可以在类中将此属性定义为virtual,以便修改其行为

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

    正如其他答复所述,您可以定义基类并定义所有继承者都可以访问的受保护属性


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

    尽管许多其他答案在语义层面是正确的,我发现从实现细节层面来处理这类问题也很有趣

    接口可以看作是插槽的集合,其中包含方法。当一个类实现一个接口时,该类需要告诉运行时如何填充所有必需的插槽。当你说

    interface IFoo { void M(); } 
    class Foo : IFoo { public void M() { ... } }
    
    这个类说:“当你创建我的一个实例时,在IFoo.M的槽中填充对Foo.M的引用

    然后当你打电话时:

    IFoo ifoo = new Foo();
    ifoo.M();
    
    编译器生成的代码显示“询问对象IFoo.M的插槽中有什么方法,并调用该方法


    如果接口是包含方法的插槽集合,那么其中一些插槽还可以包含属性的get和set方法、索引器的get和set方法以及事件的add和remove方法。但是字段不是方法。没有与字段关联的“插槽”,您可以使用字段位置的引用“填充”。因此,接口可以定义方法、属性、索引器和事件,但不能定义字段

    埃里克·利珀特说对了,我会用另一种方式来表达他的话。接口的所有成员都是虚拟的,它们都需要被继承接口的类重写。您没有在接口声明中显式地写入virtual关键字,也没有在类中使用override关键字,它们是隐含的


    virtual关键字在.NET中通过方法和所谓的v-table(方法指针数组)实现。override关键字用不同的方法指针填充v-table槽,覆盖基类生成的方法指针。属性、事件和索引器作为隐藏的方法实现。但田地并非如此。因此接口不能包含字段。

    其他人已经给出了“为什么”,所以我只想补充一点,您的接口可以定义一个控件;如果将其包装到属性中:

    interface ICar {
       int Year { get; set; }
    }
    
    class Automobile : ICar
    {
        public int Year { get; set; } // automatically implemented
    }
    
    public interface IView {
        Control Year { get; }
    }
    
    
    public Form : IView {
        public Control Year { get { return uxYear; } } //numeric text box or whatever
    }
    

    已经说了很多,但为了简单起见,这里是我的看法。 接口的目的是让方法契约由使用者或类实现,而不是让字段存储值

    你可能会争辩为什么允许房产?因此,简单的答案是-属性在内部仅定义为方法。

    从C#8.0开始,接口可以定义m的默认实现