下面的代码示例说明了我的问题。 我如何将lambda的一部分放在别处?
如何从'GetGurus()'方法调用'Foo'? 我希望LINQ将其翻译为1个语句。
public enum GuruLevel
{
NotSet,
Goku,
SuperSayan
}
private IEnumerable<PersonInfo> GetGurus()
{
using (var context = new CRMContext())
{
var persons = context.Person
.Where(p => p.Experience > 10)
.OrderBy(p => p.DateOfBirth)
.Select(p => new PersonInfo())
{
StackOverFlowName = p.StackOverFlowName,
Experience = p.Experience,
GuruStatus = Foo //(p.Experience > 9000) ? GuruLevel.SuperSayan : GuruLevel.Goku
}
return persons.ToList();
}
}
public static System.Linq.Expressions.Expression<Func<Person, GuruLevel>> Foo
{
get
{
return bar => (bar.Experience > 9000) ? GuruLevel.SuperSayan : GuruLevel.Goku;
}
}
答案 0 :(得分:1)
这个逻辑是PersonInfo
类的责任。此代码通常放在构造函数或工厂类中,并且完全符合单一责任原则。
class PersonInfo
{
public string StackOverFlowName { get; set; }
public int Experience { get; set; }
public GuruLevel GuruStatus { get; set; }
public void PersonInfo(Person p)
{
StackOverFlowName = p.StackOverFlowName;
Experience = p.Experience;
GuruStatus = p.Experience > 9000 ? GuruLevel.SuperSayan : GuruLevel.Goku;
}
}
然后将您的服务方法更改为:
private IEnumerable<PersonInfo> GetGurus()
{
using (var context = new CRMContext())
{
var persons = context.Person
.Where(p => p.Experience > 10)
.OrderBy(p => p.DateOfBirth)
.ToList()
.Select(p => new PersonInfo(p))
return persons.ToList();
}
}
或将责任转移到工厂:
public class PersonInfoFactory
{
public PersonInfo Create(Person person)
{
return new PersonInfo
{
StackOverFlowName = p.StackOverFlowName,
Experience = p.Experience,
GuruStatus = ExperienceBasedStatus(p.Experience)
};
}
private GuruLevel ExperienceBasedStatus(int experience) => experience > 9000 ? GuruLevel.SuperSayan : GuruLevel.Goku;
}
答案 1 :(得分:1)
这不是你问题的直接答案,但它与你问的原因有关。
我假设您正在使用某种DB,因此您无法使用常规方法,因为它们不会被DB的上下文所知。
例如,您实际上可以执行使用数据执行某些操作的私有方法,但您无法使用自定义类型或类。在你的例子中,'GuruLevel'将不被DB识别。
我建议不要尝试在DB端进行转换。而是以DB格式检索所需的所有数据,并在应用程序端进行转换。
using (var context = new CRMContext())
{
var persons = context.Person
.Where(p => p.Experience > 10)
.OrderBy(p => p.DateOfBirth)
.Select(p => new {p.StackOverFlowName, p.Experience }) //or whole object, or other fields if needed
.ToList() //executes query, all following code will be in a context of application not DB
.Select(p => new PersonInfo())
{
StackOverFlowName = p.StackOverFlowName,
Experience = p.Experience,
GuruStatus = GetGuruStatus(p.Experience)
}
return persons.ToList();
}
private GuruLevel GetGuruLevel(int exp)
{
return exp > 9000 ? GuruLevel.SuperSayan : GuruLevel.Goku
}
答案 2 :(得分:0)
改变这一点;
public static Func<Person, GuruLevel> Foo
{
get
{
return bar => (bar.Experience > 9000) ? GuruLevel.SuperSayan : GuruLevel.Goku;
}
}
然后;
private IEnumerable<PersonInfo> GetGurus()
{
using (var context = new CRMContext())
{
var persons = context.Person
.Where(p => p.Experience > 10)
.OrderBy(p => p.DateOfBirth)
.Select(p => new PersonInfo())
{
StackOverFlowName = p.StackOverFlowName,
Experience = p.Experience,
GuruStatus = Foo(p)
}
return persons.ToList();
}
}
只是一张纸条;这是一种奇怪的方式。你可以让Foo成为一个正常的功能,它会很好;
public GuruLevel Foo(Person bar)
{
return bar.Experience > 9000 ? GuruLevel.SuperSayan : GuruLevel.Goku;
}
...
GuruStatus = Foo(p)