Do you think “auto interface implementation” would

2019-02-10 09:20发布

问题:

Consider this:

public class interface Person : IPerson
{
  int ID { get; protected set; }
  string FirstName { get; set; }
  string LastName { get; set; }
  string FullName { get { return FirstName + " " + LastName; } }
}

And this:

public class StubPerson : IPerson
{
    int ID { get { return 0; protected set { } }
    string FirstName { get { return "Test" } set { } }
    string LastName { get { return "User" } set { } }
    string FullName { get { return FirstName + " " + LastName; } }
}

Usage:

IPerson iperson = new Person();

Or:

IPerson ipersonStub = new StubPerson();

Or:

IPerson ipersonMock = mocks.CreateMock<IPerson>();

So in effect we are declaring the IPerson interface and the Person class at the same time:

public class interface Person : IPerson

Do you think it would be useful to have this kind of support in .NET/C#?

Edit:

Due to mass confusion I think I need to clarify the proposed purpose:

Without this feature you would have to write:

interface IPerson
{
  int ID { get; }
  string FirstName { get; set; }
  string LastName { get; set; }
  string FullName { get; }
}

as well as this:

public class Person : IPerson
{
  int ID { get; protected set; }
  string FirstName { get; set; }
  string LastName { get; set; }
  string FullName { get { return FirstName + " " + LastName; } }
}

I'm not proposing any semantic change at all.

回答1:

I considered the same sort of thing a while ago, particularly for use in the case where you only have one production implementation of an interface, but you want to mock it out for testing. At the moment it ends up being a bit like the .c/.h files of yore.

I suspect in the end that the benefits of it are outweighed by the extra complexity both in the language and then reading the code afterwards. I'd still be interested in seeing it explored more thoroughly though. Even then, there are other things way higher on my priority list - better support for immutability being at the top :)



回答2:

Let me see if I am understand what you're asking:

Why can't we declare an interface:

interface IPerson
{
    string Name {get;set;}
    int ID {get;set;}
}

And classes which implement that interface will inherit its properties without having to re-declare them:

class Person : IPerson { } 
//person now has properties Name and ID

The reason you can't do this is even though the text of your interface code and your class code are very similar, they mean very different things. The interface simply says "implementor will have a string Name with getter and setter". It is the class which says "return private field when getter for name is invoked." Even if you use the auto-property shortcut to let the compiler implement that logic, it is still logic, which belongs in the class. Just because:

string Name {get;set;}

looks the same in an interface and in a class, it does not mean even remotely the same thing.

It would be very dangerous for the compiler to implement arbitrary logic to fulfill your contracts for you, instead of complaining at compile time that you haven't implemented them. It could introduce bugs very difficult to track down. Having compilers fall back to default behavior when no behavior is defined is a very, very bad idea.



回答3:

I believe Eiffel does something like this on .NET, in order to support multiple inheritance. A class declaration automatically produces a corresponding interface. When the class type is referred to, the compiler mostly emits a reference to the interface type instead. The main exception is in constructor expressions of course.



回答4:

Well I think the other answers will help you understand the use of the interface to abstract logic in different concrete classes, I also think you can accomplish something similar to what you want using the refactoring tools built into VS.

Define your class...

public class Person
{
  public int ID { get; protected set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string FullName { get { return FirstName + " " + LastName; } }
}

Then right click, select Refactor -> Extract Interface.

This will create a separate file containing the interface for the definition of the class, you could then mold the interface and implementing classes accordingly.

Extracted Interface:

interface IPerson
{
    string FirstName { get; set; }
    string FullName { get; }
    int ID { get; }
    string LastName { get; set; }
}


回答5:

I guess I am missing the point - what are you accomplishing by mixing a class and an interface together? What problem are you solving with this approach?

This:

IPerson iperson = new Person();

is already legal in C#.

Edit: For clarification - the code above is legal given the following:

interface IPerson { }

class Person : IPerson { }


回答6:

I'd at least like Visual Studio to implement my properties from an interface as auto properties if I request it to do so.

Unfortunately this option doesn't and I have to deal with Not Implemented Exception stubs



回答7:

No, because you would be forced to expose all public members of an interface. Try ReSharper, and never worry about this again.



回答8:

Resharper can provide this functionality, e.g.,

  1. You can write your Person class first.
  2. You can extract your interface by pulling members up to the IPerson interface.

Consequently you can have Visual Studio auto-generate implementation stubs for you.

UPDATE

Anyway, let's expound on interfaces first, citing the code you provided in your question:

public class interface Person : IPerson
{
    int ID { get; protected set; }
    string FirstName { get; set; }
    string LastName { get; set; }
    string FullName { get { return FirstName + " " + LastName; } }
}

You have to understand that an Interface is not an Abstract Class. An interface is merely a contract, a blueprint of sorts, which means that it will tell an object what to expect in another object without really caring about how it is implemented.

An Abstract Class, on the other hand, can contain snippets of functionality that can be inherited and overridden.

In the case above, your "interface" is invalid because:

  • you couldn't declare scope constraints on interfaces (public, private, protected, internal) as that is an implementation detail
  • you couldn't declare a default implementation (e.g., your FullName property) because again, that is an implementation detail

It appears to me what you really really want is an abstract class, e.g.,

public abstract class BasePerson
{
    public abstract int ID { get; protected set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public virtual string FullName { get { return FirstName + " " + LastName; } } 
}

I'm just guessing, but maybe that's what you really need.

UPDATE 2

Okay, I think I'm getting at what you want to happen, so what you want is to be able to write this:

public interface IPerson
{
    int ID { get; set; }
    string FirstName { get; set; }
    string LastName { get; set; }
    string FullName { get; }
}

And then for your implementation only need to write this:

public class Person : IPerson
{
    public int ID { get; protected set; }
    public string FullName { get { return FirstName + " " + LastName; } } 
}

Without needing to specify the FirstName and LastName properties.

First problem that we need to tackle is the fact that interfaces don't allow access delimiters in its implementation: what would happen is that the properties would inherit the default access delimiter, which is private.

Second is the fact that while in our eyes string FirstName { get; set; } in an interface and public string FirstName { get; set; } in a class are the same, they are actually not:

  • in an interface, the property definition will indicate that the method signatures for the getter and/or setter methods will be available for all classes implementing that interface.
  • in a class, the property definition will instruct the CLR to create an anonymous object which will hold the value of the said Property.

Subtle difference for the programmer, worlds apart for the compiler.

Lastly, when you do specify that you are implementing an interface, Visual Studio does perform synctactic magic that automatically makes those property stubs for you.



回答9:

I think a better abstraction for this is a trait, or, as I've described here, a role. This is like an interface with code. Your example could be coded like this:

public role RPerson { 
  int ID { get; protected set; } 
  string FirstName { get; set; } 
  string LastName { get; set; } 
  string FullName { get { return FirstName + " " + LastName; } } 
} 

public class Person : RPerson { }

public class StubPerson : RPerson { 
    int ID { get { return 0; protected set { } } 
    string FirstName { get { return "Test" } set { } } 
    string LastName { get { return "User" } set { } } 
    string FullName { get { return FirstName + " " + LastName; } } 
} 

// ...

RPerson rperson = new Person(); 

RPerson rpersonStub = new StubPerson();