Home > Back-end >  How do I Reference a Member of a List in C#?
How do I Reference a Member of a List in C#?

Time:09-02

I'm currently writing a program in C#/.NET and am having issues trying to reference a member of a static list in C#.

In my program, I have a class which contains static lists of objects that are displayed in my GUI. An example of the classes are as follows (note that the ellipsis (...) are there to denote more code):

using System;
using System.Collections.ObjectModel;
...
public class MyClass : INotifyPropertyChanged
{
  ...
  // the origin list contains the main objects in the program
  static private readonly ObservableCollection<MainObject> _originList = new ObservableCollection<MainObject>();
  static public ObservableCollection<MainObject> OriginList { get => _originList; }
  ...
  // the sub list contains objects derived from objects in the main list
  static private readonly ObservableCollection<SubObject> _subList = new ObservableCollection<SubObject>();
  static public ObservableCollection<SubObject> SubList { get => _originList; }
}

// definition of MainObject class 
public class MainObject : INotifyPropertyChanged
{
  private Boolean _a = false;
  public Boolean A
  {
    get => _a;
    private set { _a = value; NotifyPropertyChanged(); }
  }
  private Boolean _b = false;
  public Boolean B
  {
    get => _b;
    private set { _b = value; NotifyPropertyChanged(); }
  }
  ...
  // definition of PropertyChanged events
  ...
}

// definition of SubObject class
public class SubObject
{
  public Boolean A = false;
  public Boolean B = false;
  public SubObject(ref aFromMainObject, ref bFromMainObject)
  {
    A = aFromMainObject;
    B = bFromMainObject;
  }
}

The objects found within OriginList are bound to and displayed in a Listbox element in the GUI, the contents and amount of which must remain variable. The contents of SubList are similarly bound to a different GUI element, displaying their own properties.

Each MainObject member of the list has a pair of Boolean variables used by the GUI. I would like to reference these variables in the individual 'SubObject' instances for their own display elements. This means, when the variables of 'MainObject' change, the variables of the derived 'SubObject' must change as well.

The problem I am having, is that the compiler complains about using an indexer variable when I try to pass one of the objects to the new class:

MyClass.SubList.Add(new SubObject(ref MyClass.OriginList[0].A, ref MyClass.OriginList[0].B));

Results in:

CS0206: A property or indexer may not be passed as an out or ref parameter

The same issue arises, when I try to reference the MainObject from the OriginList apropos:

MyClass.SubList.Add(new SubObject(ref MyClass.OriginList[0]));

I've been running in circles trying to find out how to reference a member of a list, yet haven't found anything else online. Any help would be appreciated!

Contemplatively,

R.Fox


EDIT 1: I'm afraid I forgot to note, that the lists are defined as static, making the list incapable of being referenced by anything but a static constructor!

EDIT 2: Restructured the question and added a few missing details. Thanks to @JohnAlexiou and @PaulF for bringing my attention to it!

CodePudding user response:

Thanks to insightful comments and a bit of experimentation on my end, the issue of referencing an indexer has been circumvented. Referencing an indexer does not work in the first place, because only variables and objects can be referenced: an indexer is interpreted as a method.

The solution to this issue was to pass the class object itself, to the object derived from it: in this instance, a MainObject to a SubObject:

MyClass.SubList.Add(new SubObject(MyClass.OriginList[0]));

As the class object is passed as a parameter, any changes to the main instance of the object in the OriginList, will result in changes to any objects it was passed to in the SubList.

To ensure that the GUI elements of the SubList recognize changes in the OriginList as well, events can be added to the MainObject class, and assigned in the SubObject class:

public class MainObject : INotifyPropertyChanged
{
  private Boolean _a = false;
  public Boolean A
  {
    get => _a;
    private set
    {
      if (_a != value) Event_CheckBoolChange();
      _a = value;
      NotifyPropertyChanged();
    }
  }
  private Boolean _b = false;
  public Boolean B
  {
    get => _b;
    private set
    {
      if (_b != value) Event_CheckBoolChange();
      _b = value;
      NotifyPropertyChanged();
    }
  }
  ...
  // Use event handlers to help SubObjects notify their display elements when a change takes place
  public event EventHandler BoolChangeHandler;
  private void Event_CheckBoolChange()
  {
    var _handler = BoolChangeHandler;
    _handler?.Invoke(this, EventArgs.Empty);
  }
  ...
}

// definition of SubObject class
public class SubObject : INotifyPropertyChanged
{
  private readonly MainObject ObjectReference;
  public Boolean A { get => ObjectReference.A; }
  public Boolean B { get => ObjectReference.B; }

  public SubObject(MainObject mainObj)
  {
    ObjectReference = mainObj;
    ObjectReference.BoolChangeHandler  = Event_CheckBoolChange;
  }

  // Remove event connection upon destruction
  ~SubObject()
  {
    ObjectReference.BoolChangeHandler -= Event_CheckBoolChange;
  }

  // Use events to update GUI for SubObject elements automatically
  public void Event_CheckBoolChange(object sender, EventArgs e)
  {
    NotifyPropertyChanged("A");
    NotifyPropertyChanged("B");
  }
}

A massive thanks to @PanagiotisKanavos for the thought-provoking comments on removing the ref entirely from the class constructor. It was a false understanding on my part, to think that passing a non-ref class to another class would result in the instantiation of a completely new class!

  • Related