Home > OS >  How to assign a custom class with indexer attribute with C#?
How to assign a custom class with indexer attribute with C#?

Time:12-19

I have a custom class called Matrix which I have applied an indexer so it accepts assignment and reading values to and from it as a multi-dimensional array. The Matrix class constructor accepts the rows and columns as arguments for the matrix alrernative for the native array.

When I try to assign values, I get the following exception:

Stack overflow. Repeat 24101 times: at Matrix.set_Item(Int32, Int32, Int32)

The definitive code for my Matrix class is listed below.

Matrix class

class Matrix
{
  //declare the variable to hold the number of columns
  private int cols;

  //declare the variable to hold the number of rows
  private int rows;

  //define the constructor to accept the above arguments from a user and assign
  public Matrix(int rows, int cols)
  {
    this.rows=rows;
    this.cols=cols;
  }

  //apply indexing structure to this class to make it accept array operations(multidimensional)
  public int this[int rows,int cols]
  { 
    get
    {
      return matrixA[rows,cols]; 
    }

    set
    {
      matrixA[rows,cols] = value;
    } 
}

The Main

//declare the Matrix object
static Matrix matrixA;
//the lines below shows how to use the Matrix class
static void Main(string args[])
{
  Console.WriteLine("Enter the number of rows");
  int m = Int32.Parse(Console.ReadLine());

  Console.WriteLine("Enter the number of columns");
  int n = Int32.Parse(Console.ReadLine());

  matrixA = new Matrix(m, n);
 
  for (int i = 0; i < m; i  )
  {
    for (int j = 0; j < n; j  )
    {
      //i suppose the setter is invoked by this code
      matrixA[i, j] = Int32.Parse(Console.ReadLine());
    }
  }
}

CodePudding user response:

Your Matrix class doesn't actually have anywhere to store any data; put a data storage for the matrix inside the Matrix class:

class Matrix
{
  private int[,] _data;

  //define the constructor to accept the above arguments from a user and assign
  public Matrix(int rows, int cols)
  {
    _data = new int[rows,cols];
  }

  //apply indexing structure to this class to make it accept array operations(multidimensional)
  public int this[int row, int col]
  { 
    get
    {
      return _data[row,col]; 
    }

    set
    {
      _data[row,col] = value;
    } 
}

I suppose you've put your Matrix class inside your Program class (hence how Matrix's setter is able to access the static matrixA variable..) - I would say right now, to stick to a rule of "never put one class inside another". class-inside-class does work/is legal C# syntax and there are a few situations where it might be desirable but generally (and especially when beginning) it's not; avoid doing it. If you have to do it to "get something else working" then it's likely indicative of a problem elsewhere

And in the main:


static void Main(string[] args) //in c# we put [] after the type, not the argument name
{
  Console.WriteLine("Enter the number of rows");
  int m = Int32.Parse(Console.ReadLine());

  Console.WriteLine("Enter the number of columns");
  int n = Int32.Parse(Console.ReadLine());

  var matrixA = new Matrix(m, n);

  ...

As to why it all went wrong:

enter image description here

You attempt to access matrixA in the loop (red arrow) - that means you're accessing the matrixA at the top of main. You're trying to set a value so C# runs the set code. The first thing the set does is access matrixA (green line) in order to perform a set, so C# starts calls the set (blue line) which means it all just goes round and round in an endless circle, blue/green/blue/green...

Attempting to use the getter would behave the same; your code never actually gets or stores any data, because there isn't any data store, it just accesses itself over and over

This doesn't happen when you keep the data inside the class because the setter doesn't end up accessing itself; it accesses the data store instead.

In a more simplistic example:

  class Person{
     
    string name;

    void SetNameBroken(string nameToSet){
      SetNameBroken(nameToSet);
    }
 
    void SetNameWorking(string nameToSet){
      name = nameToSet;
    }
  }
  • Related