Могу ли я ограничить класс параметров шаблона для реализации интерфейсов, которые поддерживаются другими? - PullRequest
1 голос
/ 07 июня 2010

Название немного размыто, поэтому вот ситуация:

Я пишу код для использования некоторых «траекторий». Траектории - абстрактная вещь, поэтому я описываю их с помощью различных интерфейсов. Итак, у меня есть такой код:

namespace Trajectories {
    public interface IInitial<Atom>
    {
        Atom Initial { get; set; }
    }

    public interface ICurrent<Atom>
    {
        Atom Current { get; set; }
    }

    public interface IPrevious<Atom>
    {
        Atom Previous { get; set; }
    }

    public interface ICount<Atom>
    {
        int Count { get; }
    }

    public interface IManualCount<Atom> : ICount<Atom>
    {
        int Count { get; set; }
    }
    ...
}

Каждая конкретная реализация траектории будет реализовывать некоторые из вышеуказанных интерфейсов. Вот конкретная реализация траектории:

    public class SimpleTrajectory<Atom> : IInitial<Atom>, ICurrent<Atom>, ICount<Atom>        {
        // ICount
        public int Count { get; private set; }

        // IInitial
        private Atom initial;
        public Atom Initial { get { return initial; } set { initial = current = value; Count = 1; } }

        // ICurrent
        private Atom current;
        public Atom Current { get { return current; } set { current = value; Count++; } }
    }

Теперь я хочу иметь возможность делать выводы о траекториях, поэтому, например, я хочу поддержать предикаты о различных свойствах некоторой траектории:

namespace Conditions
{
    public interface ICondition<Atom, Trajectory>
    {
        bool Test(ref Trajectory t);
    }

    public class CountLessThan<Atom, Trajectory> : ICondition<Atom, Trajectory>
        where Trajectory : Trajectories.ICount<Atom>
    {
        public int Value { get; set; }
        public CountLessThan() { }

        public bool Test(ref Trajectory t)
        {
            return t.Count &lt Value;
        }
    }

    public class CurrentNormLessThan<Trajectory> : ICondition<Complex, Trajectory>
        where Trajectory : Trajectories.ICurrent<Complex>
    {
        public double Value { get; set; }
        public CurrentNormLessThan() { }

        public bool Test(ref Trajectory t)
        {
            return t.Current.Norm() &lt Value;
        }
    }
}

Теперь возникает вопрос: что, если я хочу реализовать предикат AND? Это было бы что-то вроде этого:

public class And<Atom, CondA, TrajectoryA, CondB, TrajectoryB, Trajectory> : ICondition<Atom, Trajectory>
    where CondA : ICondition<Atom, TrajectoryA>
    where TrajectoryA : // Some interfaces
    where CondB : ICondition<Atom, TrajectoryB>
    where TrajectoryB : // Some interfaces 
    where Trajectory : // MUST IMPLEMENT THE INTERFACES FOR TrajectoryA AND THE INTERFACES FOR TrajectoryB 
{
    public CondA A { get; set; }
    public CondB B { get; set; }

    public bool Test(ref Trajectory t) {
        return A.Test(t) && B.Test(t);
    }
}

Как я могу сказать: поддерживать только эти траектории, для которых аргументы AND в порядке?

Так что я могу написать:

var vand = new CountLessThan(32) & new CurrentNormLessThan(4.0);

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

1 Ответ

1 голос
/ 07 июня 2010

Вы можете полностью исключить ICondition и просто использовать предикаты и функциональный стиль.Вот пример статического способа сделать его: -

public static Predicate<T> CountLessThan<T> (int value) where T:ICount
{ 
    return (T item) => item.Count < value;
}

И вот как вы можете его использовать: -

Predicate<SimpleTrajectory> anded = x => CountLessThan<SimpleTrajectory>(5)(x) && CountLessThan<SimpleTrajectory>(3)(x);

Вы также можете создать такие методы расширения для объединения предикатов: -

public static Predicate<T> And<T>(this Predicate<T> first, Predicate<T> second)
{
    return (T item) => first(item) && second(item);
}

Альтернативой может быть базовый, абстрактный, общий класс Условий, из которого происходят другие ваши условия, а затем реализовать И, Или, ... в базовом классе условий, обеспечивающем свободный интерфейс, такой как: -

 ... = new CountLessThan(5).And(new CountLessThan(3))

Обобщение в T гарантирует, что вы можете комбинировать только условия с одинаковым T.

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