返回接口类型的扩展方法
因此,我正在编写一个简单的通用矩阵类,但遇到了一个我不喜欢我的解决方案的问题,所以我想我应该寻求更好的解决方案的帮助。
考虑此处描述的接口:
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);
}
考虑 Multiply 方法。与 IMatrix 对象相乘的结果是众所周知的。为简单起见,仅考虑矩阵的整数实现。为了计算结果,除了 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 实例。然而,这并不明显,人们可能会认为它正在更新正在调用该方法的矩阵。
是否有更好的模式可以遵循来添加构建接口的具体实现的方式?或者这个方法看起来还可以吗?
我刚刚熟悉泛型,所以如果我没有看到明显的东西,请耐心等待。
So I was writing a simple generic matrix class and ran into a problem for which I do not like my solution so I figured I'd ask for help with a better one.
Consider the interface described here:
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);
}
with extensions
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);
}
Consider the Multiply method. The result of multiplying to IMatrix objects is well known. For simplicity, consider only the integer implementation of the Matrix. In order to calculate the result, we do not need to know anything about the matrix other than how Multiply(int, int) and Add(int, int) work. Since both of them are known, I should not need anything else to return a new matrix with that result. However, I'm unsure of the best way of doing this.
My approach was to add in the two methods FromRows and FromColumns to the interface. This seems wrong since I should not force construction of the matrix in this specific way (or so I feel). However, it's the only way that I could figure out how to return an instance of this interface. I would build the matrix in the joiner class using IList and ensure that the collection was either the row or column definition and then use the FromRows method. Perhaps this will make more sense with an example:
/// <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!
}
}
So at the end of the method, I use one of the Matrices given to me to spawn a new matrix of the (probably) same type (though there is no restriction on what the matrix returns as far as the concrete implementation). There is part of the problem; the FromRows returns a NEW instance. It is not obvious, however and one may think that it is updating the matrix that the method is being called on.
Is there a better pattern to follow for adding in a way of constructing a concrete implementation of an interface? Or does this method seem OK?
I'm just getting familiar with generics so please bear with me if I'm not seeing something obvious.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Construct(int xDimension, int yDimension)
的方法,返回它的新实例就我个人而言,我会选择第二种选择。无论如何,您都是针对接口进行编码的,实现并不重要。您可以轻松返回矩阵的默认实现,并且调用者将能够使用它。此外,您还应该考虑将其应用于其他方法 - 不要操作传入的矩阵,而是创建一个新矩阵并对其进行操作。
这与 LINQ 的工作方式类似,并且可以防止 bug 潜入。如果要操作当前对象,则不需要扩展方法。
Construct(int xDimension, int yDimension)
on your interface, returning a new instance of itPersonally, I would go with the second option. You are coding against interfaces anyway, the implementation isn't supposed to matter. You are easily able to return your default implementation of a matrix and the caller will be able to work with it. Aditionally, you should think about adopting this for your other methods as well - instead of manipulating the passed in matrix, create a new one and manipulate that.
This would be similar to the way LINQ works, and would prevent bugs to sneak in on the way. If you want to manipulate the current object, you don't need extension methods.