简体   繁体   English

C#中泛型多个类型的列表class

[英]List of class of generic multiple types in C#

I'm working with a vector class who have generic type like this我正在使用一个向量 class,它具有这样的通用类型

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.我想创建一个 Matrix class,它有一个通用类型的向量列表作为属性。

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.编辑 1:这是一个通用矩阵 class。大多数方法都需要数组性能,因此它包含在向量 class 中。甚至用于从数据库中获取数据,因此需要多类型。

Actually is used with public list<Vector>.实际上与 public list<Vector> 一起使用。

I would suggest you make an abstract base class Vector and then inherit Vector<T> from it.我建议您创建一个抽象基 class Vector ,然后从中继承Vector<T> Then Matrix doesn't need to be generic.然后Matrix不需要是通用的。

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.一般来说应该够用了。

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和通用矩阵 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.我决定将它们设为readonly struct ,这样就不会发生意外修改。 Each vector/matrix is of fixed size, but their elements can be changed.每个向量/矩阵的大小都是固定的,但它们的元素是可以改变的。 I have implemented Index and Range indexing to facilitate slicing.我已经实现了IndexRange索引以方便切片。 For example: x[1..3]例如: x[1..3]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM