Общий класс для автоматического создания конкретного класса - PullRequest
1 голос
/ 21 октября 2011

Есть ли способ взять интерфейс, скажем:

/// <summary>
/// Interface containing operators which operate on T
/// </summary>
public interface IScalarOperators<T>
{
    // Adds two T objects
    IOperateScalar<T> OperatorAdd { get; }
    // Subtracts two T objects
    IOperateScalar<T> OperatorSubtract { get; }
    // Multiplies two T objects
    IOperateScalar<T> OperatorMultiply { get; }
}

// Class containing all the Scalar operators for a given T
class ScalarOperators<T> : IScalarOperators<T>
{
    public IOperateScalar<T> OperatorAdd { get; private set; }
    public IOperateScalar<T> OperatorSubtract { get; private set; }
    public IOperateScalar<T> OperatorMultiply { get; private set; }
    private ScalarOperators(IOperateScalar<T> add, IOperateScalar<T> subtract, IOperateScalar<T> multiply)
    {
        this.OperatorAdd = add;
        this.OperatorSubtract = subtract;
        this.OperatorMultiply = multiply;
    }

    public static ScalarOperators<bool> CreateBool()
    {
        return new ScalarOperators<bool>(new AddBool(), new SubtractBool(), new MultiplyBool());
    }

    public static ScalarOperators<int> CreateInt()
    {
        return new ScalarOperators<int>(new AddInt(), new SubtractInt(), new MultiplyInt());
    }

    // METHOD I WANT TO ADD
    public static ScalarOperators<T> Create()
    {
      // if T == bool
      // return CreateBool()
      // if T == int
      // return CreateInt()
      // else (no definition available for T)
      // return null
    }

    // I tried something like below, but it didn't work...
    public static ScalarOperators<T> Create<T>() where T: bool
    { return CreateBool(); }

    public static ScalarOperators<T> Create<T>() where T : int
    { return CreateInt(); }

    public static ScalarOperators<T> Create<T>()
    { return null; }
}

Обратите внимание, я бы хотел универсальный метод Create, который создает правильный набор операторов, но я не уверен, как это сделатьэто.

Я хотел бы использовать его для удаления параметра из этого метода:

    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);
    }

становится

    public static IMatrix<T> Add<T>(this IMatrix<T> matrix, IMatrix<T> other)
    {
        JoinCells<T> joiner = new JoinCells<T>();
        return joiner.Join(matrix, other, null, ScalarOperators<T>.Create().OperatorAdd);
    }

Спасибо за любую помощь!В основном, я просто не хочу передавать объект scalarOperator методу расширения, я бы предпочел иметь «default», поскольку маловероятно, что ScalarOperators изменится для любого определенного T.

Ответы [ 3 ]

3 голосов
/ 21 октября 2011

Я предлагаю создать фабрику IScalarOperators вместо статического класса (если вам действительно нужно, чтобы он был статическим, вы могли бы получить к нему доступ через статическое поле).Вы можете зарегистрировать их при запуске приложения и получить в этом примере метод:

 public IScalarOperators<T> Create<T>()
 {
    // check if exists in dictionary
    return (ScalarOperators<T>)dict[typeof(T)];
 }

dict будет иметь тип Dictionary.Преимущество состоит в том, что вы можете добавлять новые IScalarOperators во время роста приложения, только создав новый реализующий класс и зарегистрировав его на фабрике, приведение является недостатком.Также у вас будет лучшее разделение проблем и (на мой взгляд) более чистый код.

2 голосов
/ 21 октября 2011

Что вам нужно сделать, это получить тип T.

Ваш метод Create может быть таким:

public static ScalarOperators<T> Create()
{
    Type type = typeof(T); 
    if(type == typeof(bool))
      return CreateBool()
    if(type == typeof(int))
      return CreateInt()
    else
      return null
}
1 голос
/ 21 октября 2011

Здесь происходит несколько вещей, которые, я думаю, должны быть рассмотрены.Вы пытаетесь отделить свои пользовательские операторы от типов, с которыми они работают, что вводит в заблуждение, и вы пытаетесь взять очень широкую концепцию обобщения и затем специализировать их.

Для первого,вы всегда будете использовать одни и те же операторы для одного и того же типа (по крайней мере, вы никогда не будете пытаться использовать операторы bool для типа int).Нет причин усложнять вещи, имея отдельный класс для них.В последнем случае универсальные классы и универсальные методы должны работать одинаково для любого заданного T. Конечно, вы вполне можете получить typeof(T) в своем статическом методе фабрики и сравнить его с этим для нескольких конкретных случаев, а затемЯ должен изменить это для каждого нового T, который вы хотите обработать из-за этой слишком сложной универсальной структуры операндов.

Я бы рекомендовал создать универсальный интерфейс для ваших операндов и затем вместо этого реализовать оболочку для этих типов.Например, int можно обернуть следующим образом.

public interface IScalarOperators<T>
{
    IScalarOperators<T> Add (IScalarOperators<T> rightSide);
    IScalarOperators<T> Subtract (IScalarOperators<T> rightSide);
    IScalarOperators<T> Multiply (IScalarOperators<T> rightSide);
    T Unwrap();
}

public interface IMatrix<T> where T : IScalarOperators<T> { /* whatever */ }

public class CustomInt : IScalarOperators<CustomInt>
{
    private readonly int number;
    public CustomInt(int number) { this.number = number; }
    public CustomInt Unwrap() { return this; }
    public IScalarOperators<CustomInt> Add(IScalarOperators<CustomInt> rightSide) { return new CustomInt(number + rightSide.Unwrap().number); }
    public IScalarOperators<CustomInt> Subtract(IScalarOperators<CustomInt> rightSide) { return new CustomInt(number - rightSide.Unwrap().number); }
    public IScalarOperators<CustomInt> Multiply(IScalarOperators<CustomInt> rightSide) { return new CustomInt(number * rightSide.Unwrap().number); }
}

В этот момент вы можете работать с IMatrix<CustomInt> через интерфейс IScalarOperators<T> и выполнять любые необходимые операции.В качестве грубого примера, предполагая, что у вас есть открытый метод доступа с именем array, вы можете сказать IScalarOperators<T> result = matrix.array[0, 0].Add(matrix.array[0, 1]); и получить представление о сложении этих двух вместе.Затем вы можете выполнить любые дальнейшие операции над этим и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...