【问题标题】:building a fluent API or extention methods in C# for method Chaining在 C# 中为方法链接构建流畅的 API 或扩展方法
【发布时间】:2019-06-15 13:31:31
【问题描述】:

我正在尝试为方法链接构建一个流畅的 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&lt;Person&gt;,则使用当前的实现,我将能够让它工作。但我不确定如何从中获得实际结果 (IEnumerable&lt;Person&gt;)。

任何关于如何为接口中的方法构建它的想法都会很棒。

编辑。 添加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);
}

【问题讨论】:

  • 什么是 FamlyGraph?它是一家拥有所有关系的商店吗?
  • 扩展方法可能是理想的,也许有不同的方式来注入依赖?我讨厌建议使用服务定位器,但它可能会奏效。或者,如果做不到这一点,也许可以按照您的想法返回IBaseRelationships,然后在返回最终IEnumerable&lt;Person&gt; 的接口中再添加一个方法。它限制了流畅的语法,因为一旦调用了最后一个,您就需要在它之后的任何时间启动一个新链,但这可能不会在使用中变得那么糟糕。
  • 假设你不能控制 person 和 familygraph 类,引入扩展方法来转换到/从 releasionship 类可能是最简单的,所以它看起来像:person.GetRelationships(familygraph).Parents( ).Siblings().Children().ToPersons() @David - 没有看到你的评论开始,但我相信这本质上也是你的意思。
  • @thebenman IPersonRelationships ?只是公共接口就足够了
  • @AvinKavish 添加

标签: c# fluent method-chaining


【解决方案1】:

让我们从您想要公开的公共 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();

}

【讨论】:

  • 这很棒。但是让Person 对象FamilyGraph 知道是困难的,因为它是相反的。 FamilyGraph 取决于 Person 对象。而且我对每次方法调用都传递FamilyGraph 感觉不太好。
  • 那你不能从一个人开始把它链起来。您必须从FamliyGraph 开始,并拥有一个带有FamilyGraph 转发的中间类型。即FamilyGraph.query(person).Parents().Siblings().Cousins() 查询将返回类似IFamilyGraphQueryable
  • 你能告诉我FamilyGraph类和FamilyGraph.get的返回类型
猜你喜欢
  • 2018-07-30
  • 1970-01-01
  • 2011-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-22
相关资源
最近更新 更多