0

I'm not strong on c# interfaces, so this is me misunderstanding something. I have this interface (PMQIdent is just an identifier at heart):

public interface IisNamedItem2 {
    // note: is virtual
    public virtual PMQIdent name { 
            get => name; 
            private set => name = value; 
    }
}

used like this:

public class TVDeclarationStatement2 : IisNamedItem2 {
    // ctor
    public TVDeclarationStatement2(PMQIdent nameIn) =>
        name = nameIn;
}

But it complains that "the name 'name' does not exist in the current context"

As I marked the relevant part is virtual, I'd expect that to be carried into the class (edit: meaning effectively copied into the using class's definition, so it would just be there instead of me having to add it each time).

If I rewrite the interface as

public interface IisNamedItem999 {
    private PMQIdent _name;
    public virtual PMQIdent getName() => _name;
    public virtual PMQIdent sestName(PMQIdent val) =>
        _name = val;
}

It - quite reasonably - complains “Interfaces cannot contain instance fields”

What’s the right way to do this?
More importantly, what is the conceptual thing I’m missing that is making me misunderstand this?



Very helpful answers and comments all round. I've accepted Stefan's answer as it explains why I my thinking was wrong. Thanks all, and I've got some good links to read.

user3779002
  • 566
  • 4
  • 17
  • 1
    https://jeremybytes.blogspot.com/2019/09/c-8-interfaces-properties-and-default.html https://stackoverflow.com/a/53739385/34092 – mjwills Dec 27 '20 at 13:40
  • Good stuff, thanks. – user3779002 Dec 27 '20 at 13:56
  • 1
    You're falling into a "trap" by inadvertently leveraging features that became possible with "default interface members". Prior to c#8 it was invalid to declare a virtual property/method in an interface. To access what you've declared you'd have to cast to the interface `((IisNamedItem2)this).name`... But don't do that. Remove public and virtual from the property and remove the property's body `PMQIdent name { get; set; }` and you'll then have a "classic" interface definition. Also your implementation is recursive (the get/set refer to the property itself.. `name`) so it wouldn't work anyway – pinkfloydx33 Dec 27 '20 at 15:32
  • My talk of virtual was me confusing things. Ignore it. And I know about the recurse-till-overflow, BTDT! What I'm after is some way of mixing in functionality without full multiple inheritance. Kind of multiple inheritance without the inheritance part. I sort-of thought that's what interfaces did; I was wrong. – user3779002 Dec 27 '20 at 17:30

2 Answers2

1

More importantly, what is the conceptual thing I’m missing that is making me misunderstand this?

Implementing the interface just tells the class which methods and properties it has to contain. If there is you property in the interface, it isn't automatically in your class that inherits from it. That only happens when you inherit from an other class.

So if you have PMQIdent Name { get; set; } in your interface, you also have to write PMQIdent Name { get; set; } down in your class.

"Virtual" only means, that you can override this method or property in your class. In your example you could declare an other get/set for your property, than it has in your interface. You can do this using the "override" keyword in your class that inherits from the interface.

The answer from Ivan Khorin shows you the correct code for what you want to do.

Stefan
  • 75
  • 6
  • 3
    `So if you have PMQIdent Name { get; set; } in your interface, you also have to write PMQIdent Name { get; set; } down in your class.` Note it is possible to have a property that the class does _not_ have to implement - https://stackoverflow.com/a/53739385/34092 (I mean it is rarely _useful_ but it is possible). – mjwills Dec 27 '20 at 13:42
0
public interface IisNamedItem2
{
    // note: is virtual
    PMQIdent Name { get; set; }
}

public class TVDeclarationStatement2 : IisNamedItem2
{
    public virtual PMQIdent Name { get; set; }

    public TVDeclarationStatement2(PMQIdent nameIn)
    {
        Name = nameIn;
    }
}
Ivan Khorin
  • 827
  • 1
  • 5
  • 17
  • So in every class I mix-in the interface, I have to reimplement (AKA manually cut&paste) the methods in that interface to add them to the class? Doesn't that largely defeat the point of an interface? – user3779002 Dec 27 '20 at 13:26
  • @user3779002 If you have many classes that need an implementation for Name then you'll want to use an `abstract` class to handle that. Interfaces are meant to describe the API of a class, not to implement anything in it. – juharr Dec 27 '20 at 13:28
  • @juharr: C# only has single inheritance. I already have a well-established and necessary inheritance tree for this problem (it's a sort-of compiler). I can't discard that just to add names to a few disparate things. – user3779002 Dec 27 '20 at 13:30
  • 1
    @user3779002, You don't re-implement. You implement. Each implementation is different. That is the point of interface. Interface defines an api which can be implemented differently by different classes. – Mat J Dec 27 '20 at 13:32
  • 1
    @user3779002 In that case, yes you'll have to implement the `Name` property in all the classes that implement your interface. – juharr Dec 27 '20 at 13:32
  • 1
    The idea of interface is if some class implement it, user will consume all elements of your interface. So if interface says that consumer will have access to the property Name, the only way it can be done in the class that implement this interface is to declare this property. Actually c# 9.0 brings default initializations in intrrface declaration, but I don't use it for now – Ivan Khorin Dec 27 '20 at 13:33
  • @MatJ The fog'sclearing a bit now, however "You don't re-implement. You implement. Each implementation is different" - point is, I don't need to. The interface has *exactly* the implementation I want, a public getter and a private setter. I want exactly that for specific classes, and that's what the interface carries. Edit - and it seems I'm going to have to manually C&P that into every using class. – user3779002 Dec 27 '20 at 13:39
  • 1
    @user3779002 `The interface has exactly the implementation I want, a public getter and a private setter.` No it doesn't, since interfaces lack fields. So it has the _contract_ that you want - but not the _implementation_ that you want. – mjwills Dec 27 '20 at 13:45
  • @user3779002 A specification of usb c interface doesn't charge your phone, only an actual charger with usb c interface implementation does the charging. yea, the usb-c specification has exactly what you need to charge your phone, but a cow in the book doesn't eat grass. – Mat J Dec 27 '20 at 17:32