Home > OS >  List of class of generic multiple types in C#
List of class of generic multiple types in C#

Time:01-10

I'm working with a vector class who have generic type like this

public class Vector<T>:  IEnumerable<T>, IEnumerable
{
    public T[] Array { get; private set; }
    ...
}

I want to create a Matrix class who have a vector list of generic types as property.

public class Matrix
{
    public list<Vector<GenType>> Columns{get; set;}
}

Is that posible?

EDIT 1: It's a general purpose matrix class. Most of the methods needs the array performance so it is contained in the vector class. Even is used to take data from database so the multi-type is needed.

Actually is used with public list<Vector>.

CodePudding user response:

I would suggest you make an abstract base class Vector and then inherit Vector<T> from it. Then Matrix doesn't need to be generic.

public class Matrix
{
    public List<Vector> Columns { get; set; }
}

public abstract class Vector : IEnumerable
{
    public abstract IEnumerator GetEnumerator();
    public abstract Type GetScalarType();
}

public class Vector<T> : Vector, IEnumerable<T>
{
    private T[] _array { get; set; }

    public override IEnumerator GetEnumerator() =>
        ((IEnumerable<T>)_array).GetEnumerator();

    public override Type GetScalarType() =>
        typeof(T);

    IEnumerator<T> IEnumerable<T>.GetEnumerator() =>
        ((IEnumerable<T>)_array).GetEnumerator();
}

You then might end with code like this:

if (vector is IEnumerable<int> values)
{
    /* do stuff with `values` */
}

In general it should suffice.

CodePudding user response:

Of course, it is possible. Here the exact same thing I have done:

public readonly struct Vector<TNum> : ICollection<TNum>, System.Collections.ICollection
    where TNum: INumberBase<TNum>
{
    readonly TNum[] data;

    #region Factory
    public Vector(int size)
    {
        this.data = new TNum[size];
        Size = size;
    }
    public Vector(params TNum[] data)
    {
        this.data = data.ToArray();
        Size = this.data.Length;
    }
    public Vector(int size, Func<int, TNum> initalizer)
    {
        data = Enumerable.Range(0, size).Select(index => initalizer(index)).ToArray();
        Size = data.Length;
    }
    public static implicit operator Vector<TNum>(TNum[] data) => new Vector<TNum>(data);
    public static implicit operator TNum[](Vector<TNum> vector) => vector.ToArray();
    #endregion

    #region Properties
    public TNum[] Data => data;
    public int Size { get; }
    public TNum this[Index index]
    {
        get => data[index];
        set
        {
            data[index] = value;
        }
    }

    public TNum[] this[Range range]
    {
        get => data[range];
        set
        {
            var slice = data.AsSpan(range);
            value.CopyTo(slice);
        }
    }

    public Span<TNum> GetSpan(Index index) => data.AsSpan(index);
    public Span<TNum> GetSpan(Range range) => data.AsSpan(range);

    #endregion

    #region Collection
    public bool Contains(TNum item) => data.Contains(item);
    public void CopyTo(TNum[] array, int arrayIndex) => data.CopyTo(array, arrayIndex);
    public void CopyTo(Span<TNum> array, int arrayIndex) => data.AsSpan(arrayIndex).CopyTo(array);
    public IEnumerator<TNum> GetEnumerator() => data.AsEnumerable().GetEnumerator();

    public TNum[] ToArray() => data.Clone() as TNum[];
    #endregion
}

and the generic matrix class

public readonly struct Matrix<TNum> 
    where TNum: INumberBase<TNum>
{
    readonly Vector<TNum>[] data;

    #region Factory
    public Matrix(int rows, int columns)
    {
        Rows = rows;
        Columns = columns;
        this.data = new Vector<TNum>[rows];
        for (int i = 0; i < data.Length; i  )
        {
            data[i] = new Vector<TNum>(columns);
        }
    }
    public Matrix(int rows, int columns, params TNum[] byRows)
    {
        Rows = rows;
        Columns = columns;
        this.data = new Vector<TNum>[rows];
        for (int i = 0; i < data.Length; i  )
        {
            data[i] = byRows.AsSpan(columns * i, columns).ToArray();
        }
    }
    private Matrix(int rows, int columns, Vector<TNum>[] data)
    {
        Rows = rows;
        Columns = columns;
        this.data = data;
    }
    public Matrix(Vector<TNum>[] data)
    {
        Rows = data.Length;
        Columns = data.Length > 0 ? data[0].Size : 0;
        this.data = data.ToArray();
    }
    public Matrix(TNum[][] data)
    {
        Rows = data.Length;
        Columns = data.Length > 0 ? data[0].Length : 0;
        this.data = data.Select((row) => new Vector<TNum>(row)).ToArray();
    }
    public Matrix(int rows, int columns, Func<int, int, TNum> initializer)
    {
        Rows = rows;
        Columns = columns;
        this.data = new Vector<TNum>[rows];
        for (int i = 0; i < data.Length; i  )
        {
            this.data[i] = new Vector<TNum>(columns, (j) => initializer(i, j));
        }
    }

    public static implicit operator Matrix<TNum>(TNum[][] matrix) => new Matrix<TNum>(matrix);
    public static implicit operator Matrix<TNum>(Vector<TNum>[] data) => new Matrix<TNum>(data);
    #endregion

    #region Properties

    public int Rows { get; }
    public int Columns { get; }
    public TNum this[Index row, Index column]
    {
        get => data[row][column];
        set
        {
            data[row][column] = value;
        }
    }

    public TNum[] this[Index row, Range columns]
    {
        get => data[row][columns];
        set
        {
            var span = data[row].GetSpan(columns);
            value.AsSpan().CopyTo(span);
        }
    }

    public TNum[] this[Range rows, Index column]
    {
        get
        {
            var slice = data[rows];
            TNum[] result = new TNum[slice.Length];
            for (int i = 0; i < slice.Length; i  )
            {
                result[i] = slice[i][column];
            }
            return result;
        }
        set
        {
            var slice = data[rows];
            for (int i = 0; i < slice.Length; i  )
            {
                slice[i][column] = value[i];
            }
        }
    }
    public TNum[][] this[Range rows, Range columns]
    {
        get
        {
            var slice = data[rows];
            TNum[][] result = new TNum[slice.Length][];
            for (int i = 0; i < slice.Length; i  )
            {
                result[i] = slice[i][columns];
            }
            return result;
        }
        set
        {
            var slice = data[rows];
            for (int i = 0; i < slice.Length; i  )
            {
                slice[i][columns] = value[i];
            }
        }
    }

    public Vector<TNum> GetRow(Index row) => data[row];
    public Vector<TNum>[] GetRows(Range rows) => data[rows];
    public Vector<TNum> GetColumn(Index column)
    {
        TNum[] result = new TNum[data.Length];
        for (int i = 0; i < data.Length; i  )
        {
            result[i] = data[i][column];
        }
        return result;
    }
    public Vector<TNum>[] GetColumns(Range columns)
    {
        Vector<TNum>[] result = new Vector<TNum>[data.Length];
        for (int i = 0; i < data.Length; i  )
        {
            result[i] = data[i][columns];
        }
        return result;
    }

    public TNum[][] ToJaggedArray() => data.Select(row => row.ToArray()).ToArray();

    #endregion

    #region Collection
    public bool Contains(TNum value) => data.Any((row) => row.Contains(value));
    #endregion

}

I have skipped through all the algebra, and linear system solving, but it works great. I made the decision to make them a readonly struct so that there is no chance for unintended modifications. Each vector/matrix is of fixed size, but their elements can be changed. I have implemented Index and Range indexing to facilitate slicing. For example: x[1..3]

  • Related