создание свободного API или методов расширения в C # для метода Chaining - PullRequest
0 голосов
/ 15 июня 2019

Я пытаюсь создать свободный API для цепочки методов. Это методы

public interface IBaseRelationships
{
    IEnumerable<Person> Parents(IEnumerable<Person> people);
    IEnumerable<Person> Children(IEnumerable<Person> people);
    IEnumerable<Person> Siblings(IEnumerable<Person> people);
}

И реализация

   public class BaseRelationships : IBaseRelationships
    {
        public BaseRelationships(IFamilyGraph familyGraph)
        {
            FamilyGraph = familyGraph;
        }

        public IFamilyGraph FamilyGraph { get; }

        public IEnumerable<Person> Parents(IEnumerable<Person> people)
        {
            List<Person> result = new List<Person>();
            foreach (var person in people)
            {
                IPersonRelationships personRelationships = FamilyGraph.Get(person);
                result.AddRange(personRelationships.Parents);
            }
            return result;
        }
        public IEnumerable<Person> Children(IEnumerable<Person> people)
        {
            List<Person> result = new List<Person>();
            foreach (var person in people)
            {
                IPersonRelationships personRelationships = FamilyGraph.Get(person);
                List<Person> children = personRelationships.Edges.Where(m => m.RelationshipType == RelationshipType.Parent)
                    .Select(m => m.Target)
                    .ToList();
                result.AddRange(children);
            }
            return result;

        }
        public IEnumerable<Person> Siblings(IEnumerable<Person> people)
        {
            List<Person> result = new List<Person>();
            return result;
        }
    }
}

Я бы хотел сделать что-то подобное.

var person = new List<Person> {new Person()};
var cousins = person.Parents().Siblings().Children();

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

С текущей реализацией, если я верну IBaseRelationships вместо IEnumerable<Person>, я смогу заставить это работать. Но я не уверен, как я смогу получить фактический результат (IEnumerable<Person>) из него.

Любая идея о том, как построить это для методов в интерфейсе, была бы отличной.

Edit. Добавление FamilyGraph передняя ссылка

public class FamilyGraph : IFamilyGraph
{
    private Dictionary<Person, PersonRelationships> Families;
    public FamilyGraph(IPersonStore personStore)
    {
        Families = new Dictionary<Person, PersonRelationships>();
        PersonStore = personStore;
    }
    public IPersonStore PersonStore { get; }

    public void Add(EdgeInput inputEdge)
    {
        Edge edge;
        try
        {
            edge = GetEdge(inputEdge);
        }
        catch (ArgumentException)
        {
            throw;
        }
        switch (edge.RelationshipType)
        {
            case Enums.RelationshipType.Parent:
                AddParentRelationship(edge);
                return;
            case Enums.RelationshipType.Spouse:
                AddSpouseRelationship(edge);
                return;
        }
    }
    public Edge GetEdge(EdgeInput inputEdge)
    {
        Person source, target;
        try
        {
            source = PersonStore.GetPerson(inputEdge.Source);
            target = PersonStore.GetPerson(inputEdge.Target);
        }
        catch (Exception)
        {

            throw;
        }
        return new Edge(source, target, inputEdge.RelationshipType);
    }
    public IPersonRelationships Get(Person person)
    {
        PersonRelationships personRelationships;
        Families.TryGetValue(person, out personRelationships);
        return personRelationships;
    }
}

public interface IPersonRelationships
    {
        List<Edge> Edges { get; }
        List<Person> Parents { get; }
        Person Spouse { get; }

        void AddEdge(Edge edge);
        void AddParent(Person parent);
        void AddSpouse(Person spouse);
        bool CanAddParent(Person parent);
    }

public interface IPersonStore
{
    void Add(Person person);
    bool Contains(string personName);
    Person GetPerson(string personName);
}

1 Ответ

2 голосов
/ 15 июня 2019

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

var person = new Person();
var people = new List<Person> { person };
var cousins = person.Parents().Siblings().Children();
// Or
var cousins = people.Parents().Siblings().Children();

Поскольку вы хотите начать цепочку с человека /люди, этот человек должен знать о FamilyGraph, которому они принадлежат.

public class Person {

    public FamilyGraph FamilyGraph { get; set; }

    IEnumerable<Person> Parents() => FamilyGraph.Get(person).Parents;

    IEnumerable<Person> Children() => 
        FamilyGraph.Get(person).Edges
          .Where(m => m.RelationshipType == RelationshipType.Parent)
          .Select(m => m.Target)
          .ToList();

    IEnumerable<Person> Siblings() => FamilyGraph.Get(person)./* your logic here */;
}


public static class PeopleExtensions 
{
    public static IEnumerable<Person> Parents(this IEnumerable<Person> people) =>
        people.SelectMany(person => person.Parents()).ToList();

    public static IEnumerable<Person> Siblings(this IEnumerable<Person> people) =>
        people.SelectMany(person => person.Siblings()).ToList();

    public static IEnumerable<Person> Children(this IEnumerable<Person> people) =>
        people.SelectMany(person => person.Children()).ToList();

}
...