views:

1001

answers:

9

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  A: 

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 { }
Andrew Hare
I'm not sure what your point is. I know that I can declare a class and interface in the same file but I still have to declare both.
Jonathan Parker
So what you want to do is declare them at once? Wouldn't that prevent you from ever implementing that interface on any other type? And if so then why bother with an interface at all? How would you implement the IPerson interface on a second type in your example?
Andrew Hare
You should not have voted this down. Your question makes little sense, so you should not expect a resounding "YES!" answer.
Ed Swangren
@Ed if this doesn't answer his question, he's free to downvote it. He should be more articulate in explaining why, however.
Rex M
@Rex: Well, I'm free to punch someone in the face, but I probably shouldn't. You don't have to give an upvote, but I don't think it deserves a downvote. Doesn't matter anyway I guess, I gave an up, so net is still 8 points.
Ed Swangren
@Ed never heard taking away two imaginary points on an internet website being analogous to punching someone in the face, but OK :)
Rex M
A: 

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

Robin Clowers
+11  A: 

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.

Rex M
@Andrew yes, I possibly solved the puzzle! hooray for me :)
Rex M
@Rex M Do classes not expose contracts also?
Jonathan Parker
@jonathan yes and no, but I don't see how that's relevant to the question at hand. That's another discussion in itself.
Rex M
I've updated the question to hopefully clear up the confusion.
Jonathan Parker
Good response ! :)
MRFerocius
A: 

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.

Jon Limjap
That is IDE sugar (although very helpful!), I think the asker wants to know why classes don't "inherit" from their interfaces at the language level.
Rex M
Rex, touche, I expanded my answer to include the explanation re interfaces
Jon Limjap
@Jon Limjap So if I use an abstract class instead how can I create another class that inherits from BasePerson and also from another class. E.g. public class SpecialPerson : System.Web.UI.Control, BasePerson won't compile. Note I used the Control class only because it's a concrete class.
Jonathan Parker
With my solution you can still inherit from IPerson as well as Control.
Jonathan Parker
Sorry, Jonathan, but, multiple inheritance is explicitly NOT supported in C#. Multiple implementation of interfaces is not inheritance, it's merely binding multiple contracts. For classes you can't do that.
Jon Limjap
I'm not sure if Visual C++ still allows multiple inheritance, but you might want to resort to that. But for all intents and purposes what you want to do is not possible in C#, and is considered bad practice anyway.
Jon Limjap
Sorry, I used the word inheritance but should have used the word implement. My bad. Check the updates to the question. I'm not proposing any semantic change.
Jonathan Parker
+1  A: 

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; }
}
Quintin Robinson
Yes, except you now have duplication because when you wan't to change either the class or the interface you have to change the other one.
Jonathan Parker
Well to an extent, if the interface follows the class you can just make the change to the concrete class and re-extract the interface.
Quintin Robinson
+2  A: 

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.

Daniel Earwicker
Now that's really a hack.
Jon Limjap
Similar except that in my case its semantically equivalent to a class and interface.
Jonathan Parker
Is it a hack, or is it a mapping of a pre-existing complete object model onto the more rudimentary concepts provided by a new platform? :) The lack of support for true MI in the platform is a problem. Without it, interfaces are impossible to evolve. They ought to be the same as all-abstract classes.
Daniel Earwicker
+3  A: 

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 :)

Jon Skeet
Yes! That's the same thought I had. I'm starting to lean towards a philosophy where all classes must implement an interface. Haven't thought it through much though so maybe it's a candidate for another question.
Jonathan Parker
Exactly my thought as well. The one thing I miss in C# from my C++ days is some header-alike index of all classes. I like the way it promotes encapsulation, since you can change the implementation however you feel like. Im unsure about the added complexity though..
cwap
+1  A: 

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

Sekhat