开发者

Why can't C# interfaces contain fields?

For example, suppose I w开发者_开发知识库ant an ICar interface and that all implementations will contain the field Year. Does this mean that every implementation has to separately declare Year? Wouldn't it be nicer to simply define this in the interface?


Though many of the other answers are correct at the semantic level, I find it interesting to also approach these sorts of questions from the implementation details level.

An interface can be thought of as a collection of slots, which contain methods. When a class implements an interface, the class is required to tell the runtime how to fill in all the required slots. When you say

interface IFoo { void M(); } 
class Foo : IFoo { public void M() { ... } }

the class says "when you create an instance of me, stuff a reference to Foo.M in the slot for IFoo.M.

Then when you do a call:

IFoo ifoo = new Foo();
ifoo.M();

the compiler generates code that says "ask the object what method is in the slot for IFoo.M, and call that method.

If an interface is a collection of slots that contain methods, then some of those slots can also contain the get and set methods of a property, the get and set methods of an indexer, and the add and remove methods of an event. But a field is not a method. There's no "slot" associated with a field that you can then "fill in" with a reference to the field location. And therefore, interfaces can define methods, properties, indexers and events, but not fields.


Interfaces in C# are intended to define the contract that a class will adhere to - not a particular implementation.

In that spirit, C# interfaces do allow properties to be defined - which the caller must supply an implementation for:

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

Implementing classes can use auto-properties to simplify implementation, if there's no special logic associated with the property:

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


Declare it as a property:

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


Eric Lippert nailed it, I'll use a different way to say what he said. All of the members of an interface are virtual and they all need to be overridden by a class that inherits the interface. You don't explicitly write the virtual keyword in the interface declaration, nor use the override keyword in the class, they are implied.

The virtual keyword is implemented in .NET with methods and a so-called v-table, an array of method pointers. The override keyword fills the v-table slot with a different method pointer, overwriting the one produced by the base class. Properties, events and indexers are implemented as methods under the hood. But fields are not. Interfaces can therefore not contain fields.


Why not just have a Year property, which is perfectly fine?

Interfaces don't contain fields because fields represent a specific implementation of data representation, and exposing them would break encapsulation. Thus having an interface with a field would effectively be coding to an implementation instead of an interface, which is a curious paradox for an interface to have!

For instance, part of your Year specification might require that it be invalid for ICar implementers to allow assignment to a Year which is later than the current year + 1 or before 1900. There's no way to say that if you had exposed Year fields -- far better to use properties instead to do the work here.


The short answer is yes, every implementing type will have to create its own backing variable. This is because an interface is analogous to a contract. All it can do is specify particular publicly accessible pieces of code that an implementing type must make available; it cannot contain any code itself.

Consider this scenario using what you suggest:

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

We have a couple of problems here:

  • Because all members of an interface are--by definition--public, our backing variable is now exposed to anyone using the interface
  • Which myBackingVariable will MyClass use?

The most common approach taken is to declare the interface and a barebones abstract class that implements it. This allows you the flexibility of either inheriting from the abstract class and getting the implementation for free, or explicitly implementing the interface and being allowed to inherit from another class. It works something like this:

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

public abstract class MyInterfaceBase : IMyInterface
{
    int myProperty;

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


Others have given the 'Why', so I'll just add that your interface can define a Control; if you wrap it in a property:

public interface IView {
    Control Year { get; }
}


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


A lot has been said already, but to make it simple, here's my take. Interfaces are intended to have method contracts to be implemented by the consumers or classes and not to have fields to store values.

You may argue that then why properties are allowed? So the simple answer is - properties are internally defined as methods only.


Interfaces do not contain any implementation.

  1. Define an interface with a property.
  2. Further you can implement that interface in any class and use this class going forward.
  3. If required you can have this property defined as virtual in the class so that you can modify its behaviour.


Beginning with C# 8.0, an interface may define a default implementation for members, including properties. Defining a default implementation for a property in an interface is rare because interfaces may not define instance data fields.

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


For this you can have a Car base class that implement the year field, and all other implementations can inheritance from it.


An interface defines public instance properties and methods. Fields are typically private, or at the most protected, internal or protected internal (the term "field" is typically not used for anything public).

As stated by other replies you can define a base class and define a protected property which will be accessible by all inheritors.

One oddity is that an interface can in fact be defined as internal but it limits the usefulness of the interface, and it is typically used to define internal functionality that is not used by other external code.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜