0

I want to use a static List with an interface in .net

I wonder where in the code I should declare my List : in the interface class, in the derived classes, or somewhere else ?

For the moment I have it declared in the derived class (BacFlo).

My problem is : I can't populate the List correctly, it seems like the List is empty when it shouldn't.

Here is an extract of my code :

Interface :

 public interface Serre
    {
        void Plant(Plante p);
        void Remove(string s);
        void Water(string s);
        void Clone(string s);
        void Inventory();
    }

Derived Class #1 :

public class BacFlo : Serre
    {
        static List<Plante> Garden = new List<Plante>();

        }

My main class :

    Serre bc = new BacCro();
    Serre bf = new BacFlo();

for (int i = 0; i < 10; i++)
        {
            Plante p = new Plante("Plante commune", "Vivace", "Une plante", 120);
            bf.Plant(p);
            bc.Plant(p);
        }

        for (int i = 0; i < 10; i++)
        {
            Plante p = new Plante("Plante rare", "à bulbe", "Une plante", 10);
            bf.Planter(p);
            bc.Planter(p);
        }

        bf.Inventory();
        bc.Inventory();

}

   void Serre.Inventory()
        {
            Console.WriteLine("");
            Console.WriteLine("Inventaire du bac de floraison :");
            foreach (Plante p in Jardin)
            {
                Console.WriteLine("Plante de nom " + p.Name + ", de type " + p.Type + ", de description " + p.Description + ", de taille " + p.Taille + ", Arrosée : " + (p.IsWet == true ? "Oui" : "Non"));
        }

What I want to achieve is correctly populate the List with my for loop and have displayed the inventory with the appropriate method.

I'm not sure about the instanciation of a static List...

Gui Gui
  • 7
  • 2
  • 5
    Please clarify what you're actually trying to *achieve* - and reduce your code to a minimal example, ideally using English member names for clarity. It's unclear to me how the interface is relevant to the rest of the question. – Jon Skeet Jun 29 '23 at 07:20
  • 1
    We see an interface but not how the methods are implemented.Those implementations presumably update the Garden List but we don't see that and when there is a problem its presumably in there. – Ralf Jun 29 '23 at 07:31
  • 1
    There seems to be a misconception of OOP concepts here. `public class BacFlo : Serre` is not "deriving". `BacFlo` _implements_ `Serre`. Interfaces ( `interface` keyword ) _cannot_ have (static) _Fields_. And if you make the `Garden` static on `BacFlo`, the single instance of it is going to be shared among _all_ instances of `BacFlo`. – Fildor Jun 29 '23 at 07:31
  • It's unclear how type `BacCro` plays into this. ^^ If it just implements the same interface `Serre` then it still is not a `BacFlo` and therefore does _not_ share the list. – Fildor Jun 29 '23 at 07:37
  • Alright, I have only one instance of BacFlo. – Gui Gui Jun 29 '23 at 07:38
  • Yes BacCro is similar to BacFlo, that's why I just chose to not display it ^^ – Gui Gui Jun 29 '23 at 07:39
  • If you _want_ all BacFlo and BacCro to be accessing the _same_ list, you may inject a reference to a list instance into their respective constructors. Just be careful if you go multi-threaded. Then this may lead to race conditions if not properly handled. – Fildor Jun 29 '23 at 07:41
  • 3
    People can't help if the code is missing and the question mixes up terms. Interfaces don't hold data. The word *matters* - they're interfaces the same way HDMI and USB-C are interfaces. They specify how you interact with a device or class. Devices and cables implement those interfaces, they aren't the interfaces. If you want multiple types to inherit data members they need to inherit from a class. – Panagiotis Kanavos Jun 29 '23 at 07:43
  • 2
    Inheritance specifies an `is-a` relation though. It's not a method for two classes to communicate through a static field. – Panagiotis Kanavos Jun 29 '23 at 07:45
  • What Panagiotis says plus you want to put composition before inheritance, anyway (as a _rule of thumb_). – Fildor Jun 29 '23 at 07:47
  • I provided all the relevant code snippets I believe, except the BacCro but BacCro is nearly the same as BacFlo. I do get your point, I misconfused interface and regular classes. BUT that doesn't explain why my Garden List can't be populated,with Plantes which is my original question. – Gui Gui Jun 29 '23 at 07:49
  • 1
    Seems to me like you're misunderstanding some basic concepts of c# as an object-oriented language - I suggest you should read about static members, interfaces, polymorphism and stuff like that. – Zohar Peled Jun 29 '23 at 08:01
  • `My problem is : I can't populate the List correctly, it seems like the List is empty when it shouldn't.` Why the focus on static here? Its presumably not the correct concept but isn't directly connected to his problem. He is talking about not beeing able to populate the List but we don't see anything that does it. We need to see that, help fixing that and then maybe talk about the other problems. – Ralf Jun 29 '23 at 08:21
  • We need to see the implementation of the method ```BacFlo.Plant``` and ```BacFlo.Planter``` in order to help – Shazi Jun 29 '23 at 10:20

2 Answers2

1

What it seems you have is some sort of Garden concept, which is basically a collection of Plants. And Serre seems to interface how to interact with Gardens.

I am not sure about how the BacXYZ family of classes is related to this, but you seem to want a group (if not all) instances of BacXYZ classes to interact with the same Garden. (Maybe think about that you later on may want different groups of BacXYZ to act upon different Gardens?)

So, the natural thing for me would be to either

  • include the Garden as an argument to Serre's methods or
  • inject the Garden to each BacXYZ instance upon creation.

As I suspect you will be leaning to the latter one:

You could do this:

public class BacFlo : Serre
{
    private readonly ICollection<Plant> _garden;
    
    public BacFlo( ICollection<Plant> garden )
    {
        ArgumentNullException.ThrowIfNull(garden);
        _garden = garden;
    }

    // Serre-Implementations here
}

Now, in the caller:

public void Main()
{
    var garden = new List<Plant>(); // Could also be a class field or whatever

    var bac1 = new BacFlo(garden);
    var bac2 = new BacFlo(garden);
    var bac3 = new BacFlo(garden);
}

^^ All of these would operate on the same garden list. No static needed.

Fildor
  • 14,510
  • 4
  • 35
  • 67
  • Thank you you clarified it a lot. That's much closer to what I want to achieve. Will defnitely test your method. – Gui Gui Jun 30 '23 at 03:15
  • So I tried that and It fixed my ArgumentNullException ! Thanks – Gui Gui Jun 30 '23 at 03:26
  • Just a question though : is `ArgumentNullException.ThrowIfNull(garden);` equivalent to a try{} catch() block ? – Gui Gui Jun 30 '23 at 03:36
  • That's the equivalent to `if( garden is null ) throw new ArgumentNullException(nameof(garden));` - so basically only a Null-Check to make sure DI works. – Fildor Jun 30 '23 at 06:42
0

This usage of keyword "static" seems unnecessary to me. In most cases root variable members in classes are declared Public, Private or Protected.

Here is related question on Stack Overflow

Being you I would used Private instead of Static. Behaviour of Static variables may have strange effects on programming logic. Using keyword Static mostly have some sense when in the function / procedure scope, but its usage is marginal. I can't imagine reason for declaring instance of List in class Static, you may need to do some research on Static, Private, Public and Protected, before you decide e.g. for using Static

  • `static` has nothing to do with access modifiers (`private`, `public` and so on). There are quite a few valid use-cases for static members though I agree it's probably not the case here. – Zohar Peled Jun 29 '23 at 07:54
  • @Zohar Peled: I know, that Static has nothing to do with Public and Private, but if you were beginner, you should begin with access modifiers, and end with Static. – Matěj Kasper Jun 29 '23 at 08:00