LSP касается инвариантов.
классический пример дан следующим объявлением псевдокода (опущенные реализации):
class Rectangle {
int getHeight()
void setHeight(int value)
int getWidth()
void setWidth(int value)
}
class Square : Rectangle { }
Теперь у нас есть проблема, хотя интерфейс соответствует. Причина состоит в том, что мы нарушили инварианты, происходящие от математического определения квадратов и прямоугольников. Путем методы get и работа методов set, Rectangle
должны удовлетворить следующий инвариант:
void invariant(Rectangle r) {
r.setHeight(200)
r.setWidth(100)
assert(r.getHeight() == 200 and r.getWidth() == 100)
}
Однако этот инвариант должен быть нарушенным корректной реализацией Square
, поэтому это не допустимая замена Rectangle
.
В итоге я выбрал очень простой подход, который был рекомендован в ответе, который был удален позже:
var vote = (from vote in db.Vote
where vote.Voter.Id == user.Id
select v).FirstOrDefault();
if (vote == null) {
vote = new Vote() { .... };
db.AddToVoteSet(vote);
}
Просто добавьте значение по умолчанию перед получением первого элемента.
var vote = db.Vote
.Where(v => v.Voter.Id == user.Id)
.DefaultIfEmpty(defaultVote)
.First();
Обратите внимание, что теперь вы можете безопасно использовать First ()
вместо FirstOrDefault ()
.
UPDATE
] LINQ to Entity не распознает метод расширения DefaultIfEmpty ()
. Но вы можете просто использовать нулевой оператор объединения.
var vote = db.Vote.FirstOrDefault(v => v.Voter.Id == user.Id) ?? defaultVote;
Добавьте собственный метод расширения . Например:
public static class Extension
{
public static T FirstOrDefault(this IEnumerable<T> sequence, T defaultValue)
{
return sequence.Any() ? sequence.First() : defaultValue;
}
}
С этим классом в области видимости вы можете сказать:
var vote = (from vote in db.Vote where
vote.Voter.Id == user.Id
select v).FirstOrDefault(yourDefaultValue);
Конечно, ваш метод также может иметь перегрузку, которая возвращает значение по умолчанию (T), если это было то, что вы искали. Во встроенном классе Extension уже определен метод расширения DefaultIfEmpty, поэтому я назвал этот метод в примере «FirstOrDefault», что мне кажется более подходящим.
Другой подход, если Vote
является ссылочным типом и, таким образом, использует null в качестве значения по умолчанию, будет использовать оператор объединения с нулевым значением:
var vote = (db.Vote
.Where(v => v.Voter.Id == user.Id)
.FirstOrDefault()) ?? defaultVote;
По какой-то причине, если я превращаю набор результатов в список, Defaultifempty () работает, я не знаю, случайно ли я перешел в область Linq.
var results = (from u in rv.tbl_user
.Include("tbl_pics")
.Include("tbl_area")
.Include("tbl_province")
.ToList()
where u.tbl_province.idtbl_Province == prov
select new { u.firstName, u.cellNumber, u.tbl_area.Area, u.ID, u.tbl_province.Province_desc,
pic = (from p3 in u.tbl_pics
where p3.tbl_user.ID == u.ID
select p3.pic_path).DefaultIfEmpty("defaultpic.jpg").First()
}).ToList();