具有动态功能<>构造的C#Fluent API
作者:互联网
我正在为创建一个具有流畅API的小型SQL库而烦恼,并希望做到这样的事情:
var person = connection.GetOne<Person>("select * from [Person] where [Id] = 1")
.WithMany<Pet>("select * from [Pet] where [PersonId] = 1")
.WithMany<Address>("select * from [Address] where [PersonId] = 1]")
.Build((person, pets, addresses) =>
{
person.Pets = pets;
person.Addresses = addresses;
return person;
});
我之前已经构建了大量流畅的API,但所有这些都更加简单,并且不那么依赖于泛型.我的问题是具体如何实现Build()结束函数.我不确定它是否可能(似乎不是这样但是使用Expression可能是关键?)但是如何跟踪对更高链方法的调用中指定的泛型类型(例如GetOne<> (),WithMany<>())以便在调用.Build()时使用Func<>那是必需的是正确的类型?
在上面的例子中,我想要Func<>成为Func< Person,IEnumerable< Pet>,IEnumerable< Address>>这样开发人员可以以他们需要的任何方式构造根项(人) – 在这种情况下,使用一个>多个查询的结果填充一些集合.
有没有办法做到这一点,还是我运气不好?似乎很多地方我都希望类似的东西可以做到:
Func<In1, TResult>
Func<In1, In2, TResult>
Func<In1, In2, In3, TResult>
...etc, etc
…显然将您限制为函数的最大参数数量的事物类型.
任何帮助或指针将不胜感激.
解决方法:
如果你想要强大的自动完成功能并且阻止有人在你期待(人,宠物)=>时编写.Build(person => {}). {},您需要在构建器中使用详细信息.
以下是三个级别的示例:
class Person { public IEnumerable<Pet> Pets { get; set;} } class Pet {} class Address{}
public static class Builder
{
public static Level1<T> GetOne<T>(this object obj, string blah) {
return new Level1<T>();
}
}
public class Level1<T1> {
public Level2<T1, T2> WithMany<T2>(string blah) { return new Level2<T1, T2>(); }
public T1 Build(Func<T1, T1> pred) { return pred(default(T1)); }
}
public class Level2<T1, T2>
{
public Level3<T1, T2, T3> WithMany<T3>(string blah) { return new Level3<T1, T2, T3>(); }
public T1 Build(Func<T1, IEnumerable<T2>, T1> pred) { return pred(default(T1), default(IEnumerable<T2>)); }
}
public class Level3<T1, T2, T3>
{
public T1 Build(Func<T1, IEnumerable<T2>, IEnumerable<T3>, T1> pred) {
return pred(default(T1), default(IEnumerable<T2>), default(IEnumerable<T3>));
}
}
我们在这里得到强有力的打字:
obj.GetOne<Person>("select * from [Person] where [Id] = 1")
.WithMany<Pet>("select * from [Pet] where [PersonId] = 1")
.WithMany<Address>("select * from [Address] where [PersonId] = 1]")
.Build((person, pets, addresses) => {
person.Pets = pets;
return person;
});
要么
obj.GetOne<Person>("select * from [Person] where [Id] = 1")
.WithMany<Pet>("select * from [Pet] where [PersonId] = 1")
.Build((person, pets) => { return person; });
关于有限数量参数的说明 – 这是正确的.不幸的是,我不相信在保持强力打字的同时解决这个问题.
标签:c,func,fluent-interface,generics 来源: https://codeday.me/bug/20190710/1429070.html