【问题标题】:How do Auto-Implemented properties work in C# interfaces?自动实现的属性如何在 C# 接口中工作?
【发布时间】:2020-01-08 20:10:01
【问题描述】:

如果我在 C# 类中声明 Auto-Implemented 属性,那么 public string Property { get; set; } 变为:

private string _property;

public string get_Property() {
    return _property;
}

public void set_Property(string value) {
    _property = value;
}

其中包括一个私有字段string _property

如果我创建一个接口,我可以像这样使用自动实现的属性:

string Property { get; set; }

为什么我可以在 Interface 中声明 Auto-Implemented 属性,但我不能使用更长、更冗长的语法来声明私有字段?我知道这样的定义:

接口仅包含方法、属性、事件或索引器的签名

接口中的私有字段与类中生成的私有字段不同吗?是生成的吗?

【问题讨论】:

  • 它们没有在接口中实现。接口只定义了合约。
  • 接口中的get;set; 语法只是说“实现此接口的对象必须具有您可以设置和获取的属性”。

标签: c#


【解决方案1】:

为什么我可以在接口中声明自动实现的属性

它们不是自动实现的,只是属性declaration的语法与自动实现的属性definition的语法相同。

这个:

interface IFoo
{
    String Bar { get; set; }
}

意思是:“IFoo 有一个 public[1]String 属性名为 Bar,它有一个 getter 和一个 setter。”

这个:

class Foo
{
    String Bar { get; set; }
}

意思是:“Foo 有一个 private[2]String 属性,名为 Bar,它有一个 getter 和一个 setter,以及 getter 和 setter都是由编译器自动生成的,并且对隐藏的实例字段进行操作。


请注意,接口中使用的语法与classstruct 中实现使用的语法无关。所以给定与上面相同的IFoo...

interface IFoo
{
    String Bar { get; set; }
}

...我们可以有:

// Using auto-implemented property:
class Foo2 : IFoo
{
    public String Bar { get; set; }
}
// Using explicit backing field:
class Foo3 : IFoo
{
    private String bar;

    public String Bar
    {
        get { return this.bar; }
        set { this.bar = value; }
    }
}
// Using expression-body syntax with a backing field:
class Foo4 : IFoo
{
    private String bar;

    public String Bar
    {
        get => this.bar;
        set => this.bar = value;
    }
}
// Using explicit interface implementation with a backing field:
class Foo5 : IFoo
{
    private String bar;

    String IFoo.Bar
    {
        get { return this.bar; }
        set { this.bar = value; }
    }
}

// You can also use explicit interface implementation with an auto-implemented property:
class Foo6 : IFoo
{
    String IFoo.Bar { get; set; }
}
// However, if it's a getter-only property you won't be able to set a property value in the constructor - but you can initialize it inline:
interface IReadOnlyFoo
{
    String Bar { get; }
}

class Foo7 : IReadOnlyFoo
{
    String IReadOnlyFoo.Bar { get; } = "foo"; // ok
}

class Foo8 : IReadOnlyFoo
{
    public Foo8()
    {
        this.Bar = "foo"; // <-- Error. `Bar` is not a member of `this`.
        // You also can't cast `(IReadOnlyFoo)this` because `IReadOnlyFoo` does not contain a setter.
    }

    String IReadOnlyFoo.Bar { get; }
}

接口中的私有字段是否与类中生成的不一样

接口没有字段,接口只有虚拟方法(或者更确切地说:interface 可以被认为是单个 vtable)。请注意,在内部:属性和事件也基本上是虚拟方法(另请注意,虽然它们在内部是虚拟调用,但实现的接口方法不会自动virtual(在 C# 意义上),因为接口实现的子类不能任意@ 987654342@任意接口成员[3].

也不要与 C# 8.0 中的“默认接口实现”混淆,后者更类似于扩展方法而不是将接口视为类,因为接口仍然不能有字段。

您还应该熟悉 C# 的表达式体成员语法(尽管它不常用于属性设置器):

class Foo2
{
    String bar; // this is a private instance field

    String Bar // this is a private instance property
    {
        get => this.bar;
        set => this.bar = value;
    }
}

[1] 当然,忽略显式接口实现。
[2] 如果类成员没有显式访问修饰符,则默认情况下它们是私有的。
[3] 子类可以重新实现一个接口,该接口将具有覆盖对该接口成员的任何虚拟调用的效果,但如果该成员是通过接口引用而不是通过对类的超类型。

【讨论】:

  • 接口内部的String Bar { get; set; } 语法在 C# 3.0 之前是否存在,在它作为类的自动实现属性语法存在之前?
  • @miran80 String Bar { get; set; } 语法自 C# 1.0 以来就存在,因为它用于接口属性,但是直到 C# 3.0 才支持类属性(作为自动实现的属性),并在 C# 中再次扩展4.0.
  • @dai,你提到属性不是自动实现的,它们只是声明,你能帮我理解什么时候这不是声明而是实现的。来自 Microsoft 文档 - [链接] docs.microsoft.com/en-us/dotnet/csharp/programming-guide/… - 在 C# 3.0 及更高版本中,当属性访问器中不需要额外的逻辑时,自动实现的属性使属性声明更加简洁。
  • 他们还提到 - 您不能在接口中声明自动实现的属性。自动实现的属性声明私有实例支持字段,并且接口可能不声明实例字段。在不定义主体的情况下在接口中声明属性会声明具有访问器的属性,该访问器必须由实现该接口的每种类型实现。声明一个没有正文的属性不是自动实现的属性,如果这就是为什么微软说不能在接口中声明自动实现的属性,因为这就是自动实现的属性,一个没有正文的属性。
  • @RajeevVerma 属性的“自动实现”是一个实现细节——接口(根据定义)与实现细节无关。我想你误解了什么是接口。
猜你喜欢
  • 2021-04-14
  • 2018-08-21
  • 2017-04-03
  • 2010-12-08
  • 2016-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多