简体   繁体   中英

How do Auto-Implemented properties work in C# interfaces?

If I declare Auto-Implemented properties in C# classes, then public string Property { get; set; } public string Property { get; set; } public string Property { get; set; } becomes:

private string _property;

public string get_Property() {
    return _property;
}

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

which includes a private field string _property .

If I create an interface, I am allowed to use Auto-Implemented properties like so:

string Property { get; set; }

Why can I declare Auto-Implemented properties inside Interface, but I can't use the longer, more verbose syntax that declares private fields? I am aware of the definition that says:

An interface contains only the signatures of methods, properties, events or indexers

Is the private field in interfaces not generated the same as in classes? Is it generated at all?

Why can I declare Auto-Implemented properties inside Interface

They aren't auto-implemented, it's just that the syntax of a property declaration is identical to the syntax for an auto-implemented property definition .

This:

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

Means: " IFoo has a public [1] String property named Bar which has a getter and a setter."

This:

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

Means: " Foo has a private [2] String property named Bar which has a getter and a setter, and the getter and setter are both auto-generated by the compiler and operate on a hidden instance field.


Note that the syntax used in the interface is unrelated to the syntax used by implementation in the class or struct . So given the same IFoo as above...

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

...we can have:

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

Is the private field in interfaces not generated the same as in classes

Interfaces don't have fields, interfaces only have virtual methods (or rather: an interface can be thought-of as a single vtable). Note that internally: properties and events are also fundamentally virtual methods (also note that while internally they're virtual calls, implemented interface methods are not automatically virtual (in the C# sense) in that a subclass of an interface implementation cannot arbitrarily override any interface member [3] .

Also not to be confused with "Default interface implementations" in C# 8.0 which a more akin to extension methods than treating interfaces as classes, because interfaces still cannot have fields.

You should also familarise yourself with C#'s expression-bodied member syntax (though it isn't used much for property-setters):

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] Disregarding Explicit Interface Implementation, of course.
[2] Class members are private by default if they don't have an explicit access-modifier.
[3] Subclasses can reimplement an interface which will have the effect of overriding any virtual-calls to that interface member, but only if the member is accessed through an interface reference rather than through an object reference to the class's supertype.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM