【问题标题】:Extension Methods which return interface type返回接口类型的扩展方法
【发布时间】:2011-10-21 15:20:41
【问题描述】:

所以我正在编写一个简单的通用矩阵类,遇到了一个我不喜欢我的解决方案的问题,所以我想我会寻求更好的帮助。

考虑这里描述的接口:

public interface IMatrix<T>
{
    void DeleteColumn(int position);
    void DeleteRow(int position);
    // Returns a NEW IMatrix<T>
    IMatrix<T> FromRows(IList<IList<T>> rows);      // would like to remove
    // Returns a NEW IMatrix<T>
    IMatrix<T> FromColumns(IList<IList<T>> columns);// would like to remove
    IList<IList<T>> GetColumns();
    IList<IList<T>> GetRows();
    void InsertColumn(int position);
    void InsertRow(int position);
    void SetValueAt(int row, int column, T value);
}

带有扩展名

public static class MatrixExtensions
{
    /// <summary>
    /// Performs a standard matrix addition
    /// </summary>
    public static IMatrix<T> Add<T>(this IMatrix<T> matrix, IMatrix<T> other, IScalarOperators<T> operators)
    {
        JoinCells<T> joiner = new JoinCells<T>();
        return joiner.Join(matrix, other, null, operators.OperatorAdd);
    }

    /// <summary>
    /// Adds a row to the end of the matrix
    /// </summary>
    public static void AddRow<T>(this IMatrix<T> matrix);

    /// <summary>
    /// Adds a number of rows to the end of the matrix
    /// </summary>
    public static void AddRows<T>(this IMatrix<T> matrix, int rows);

    /// <summary>
    /// Adds a column to the end of the matrix
    /// </summary>
    public static void AddColumn<T>(this IMatrix<T> matrix);

    /// <summary>
    /// Adds a number of columns to the end of the matrix
    /// </summary>
    public static void AddColumns<T>(this IMatrix<T> matrix, int columns);

    /// <summary>
    /// Gets the column at the specified position
    /// </summary>
    public static IList<T> ColumnAt<T>(this IMatrix<T> matrix, int position);

    /// <summary>
    /// Gets the number of columns in the matrix
    /// </summary>
    public static int ColumnCount<T>(this IMatrix<T> matrix);

    /// <summary>
    /// Sets the number of columns in the matrix
    /// </summary>
    public static void ColumnCount<T>(this IMatrix<T> matrix, int columns);

    /// <summary>
    /// Deletes the last column from the matrix
    /// </summary>
    public static void DeleteLastColumn<T>(this IMatrix<T> matrix);

    /// <summary>
    /// Deletes the last row from the matrix
    /// </summary>
    public static void DeleteLastRow<T>(this IMatrix<T> matrix);

    /// <summary>
    /// Gets the value at the specified position in the matrix
    /// </summary>
    public static T GetValueAt<T>(this IMatrix<T> matrix, int row, int column);

    /// <summary>
    /// Multiplies this matrix with the other matrix and returns the result
    /// </summary>
    public static IMatrix<T> Multiply<T>(this IMatrix<T> matrix, IMatrix<T> other, IVectorOperators<T> vectorOperators, IScalarOperators<T> scalarOperators)
    {
        JoinRowColumn<T> joiner = new JoinRowColumn<T>();
        return joiner.Join(matrix, other, vectorOperators.OperatorAdd, scalarOperators.OperatorMultiply);
    }

    /// <summary>
    /// Gets the row at the specified position
    /// </summary>
    public static IList<T> RowAt<T>(this IMatrix<T> matrix, int position);

    /// <summary>
    /// Gets the number of rows in the matrix
    /// </summary>
    public static int RowCount<T>(this IMatrix<T> matrix);

    /// <summary>
    /// Sets the number of rows in the matrix
    /// </summary>
    public static void RowCount<T>(this IMatrix<T> matrix, int rows);
}

考虑乘法。与 IMatrix 对象相乘的结果是众所周知的。为简单起见,仅考虑 Matrix 的整数实现。为了计算结果,除了 Multiply(int, int) 和 Add(int, int) 的工作原理之外,我们不需要知道有关矩阵的任何信息。由于它们都是已知的,因此我不需要任何其他东西来返回具有该结果的新矩阵。但是,我不确定最好的方法。

我的方法是在接口中添加 FromRows 和 FromColumns 这两个方法。这似乎是错误的,因为我不应该以这种特定方式强制构建矩阵(或者我觉得)。但是,这是我弄清楚如何返回此接口的实例的唯一方法。我将使用 IList 在连接器类中构建矩阵,并确保集合是行或列定义,然后使用 FromRows 方法。举个例子也许会更有意义:

/// <summary>
/// Class used for joining by combining rows and columns
/// </summary>
/// <typeparam name="T">
/// Type of the values contained in the matrix
/// </typeparam>
class JoinRowColumn<T> : IJoinMatrix<T>
{
    public IMatrix<T> Join(IMatrix<T> a, IMatrix<T> b, IOperateVector<T> vectorOperation, IOperateScalar<T> cellOperation)
    {
        // ensure that the matricies can be joined
        if (a.ColumnCount() != b.RowCount())
        {
            throw new ArgumentException("Cannot join matricies.  Invalid dimensions");
        }

        IList<IList<T>> rowDefinition = IMatrixHelpers.GetRowDefinition<T>(a.RowCount(), b.ColumnCount());
        for (int row = 0; row < a.RowCount(); row++)
        {
            IList<T> aRow = a.RowAt(row);
            for (int col = 0; col < b.ColumnCount(); col++)
            {
                IList<T> bCol = b.ColumnAt(col);
                rowDefinition[row][col] = vectorOperation.Operate(aRow, bCol, cellOperation);
            }
        }
        // I do not like this because it is unclear that the
        // method is returning a NEW instance of IMatrix<T>
        // based on the row definition.  It does not update
        // a to contain the matrix defined by rowDefinition
        return a.FromRows(rowDefinition); // UGLY!
    }
}

所以在方法结束时,我使用给我的矩阵之一来生成(可能)相同类型的新矩阵(尽管就具体实现而言,矩阵返回的内容没有限制) .有部分问题; FromRows 返回一个 NEW 实例。然而,这并不明显,人们可能会认为它正在更新调用该方法的矩阵。

是否有更好的模式来添加构建接口的具体实现?或者这个方法看起来可以吗?

我刚刚熟悉泛型,所以如果我没有看到明显的东西,请多多包涵。

【问题讨论】:

    标签: generics interface extension-methods


    【解决方案1】:
    • 在您的界面中包含一个名为 Construct(int xDimension, int yDimension) 的方法,并返回它的一个新实例
    • 设计一个在这种情况下使用的默认实现。当您针对接口进行编码时,任何人都不应假设特定的实现。

    就个人而言,我会选择第二个选项。无论如何,您都在针对接口进行编码,实现并不重要。您可以轻松地返回矩阵的默认实现,并且调用者将能够使用它。此外,您还应该考虑将其用于您的其他方法 - 不要操作传入的矩阵,而是创建一个新矩阵并对其进行操作。

    这将类似于 LINQ 的工作方式,并且可以防止错误在途中潜入。如果要操作当前对象,则不需要扩展方法。

    【讨论】:

    • 我考虑过返回一个默认实现,然后我在想,“如果我选择的默认值是次优的怎么办......”我认为这还为时过早,有点尴尬:(
    • 不,不是。我已经无法计算我手上的次优解决方案的数量了。次优解决方案不是问题,如果您确实意识到它们并对其进行改进。我们在编码的同时都在学习,这就是我们的职业的运作方式。
    猜你喜欢
    • 2017-03-19
    • 1970-01-01
    • 2018-07-13
    • 1970-01-01
    • 2014-09-08
    • 2017-05-09
    • 1970-01-01
    • 2011-05-16
    • 2011-12-13
    相关资源
    最近更新 更多