如何避免在短If中重复Lambda表达式

本文关键字:Lambda 表达式 If 何避免 | 更新日期: 2023-09-27 18:06:45

是否有一种方法可以避免在短if内两次编写lambda表达式?我经常发现自己处于这种情况,我知道的唯一方法就是再写一遍!

为了给出一个例子,这里有一个我需要检查字符串长度的例子!

communications.Select(c => new XElement("node",
    new XAttribute("guid", Guid.NewGuid()),
    new XAttribute("title", c.CommunicationDetails.Where(x => x.CultureCode == culture).FirstOrDefault().Title.Length < 40 ? c.CommunicationDetails.Where(x => x.CultureCode == culture).FirstOrDefault().Title : c.CommunicationDetails.Where(x => x.CultureCode == culture).FirstOrDefault().Title.Substring(0, 40)),
    new XAttribute("isHidden", false))))

如何避免在短If中重复Lambda表达式

Func<IEnumerable<CommunicationDetails>, string> getFirstDtlTitle = ((dtls) => dtls.Where(x => x.CultureCode == culture).FirstOrDefault()?.Title ?? "");
communications.Select(c => new XElement("node",
                               new XAttribute("guid", Guid.NewGuid()),
                               new XAttribute("title", getFirstDtlTitle(c.CommunicationDetails).Length < 40 ? getFirstDtlTitle(c.CommunicationDetails) : getFirstDtlTitle(c.CommunicationDetails).Substring(0, 40)),
                               new XAttribute("isHidden", false))))

将是重构的第一步。

虽然我也会为字符串做一个扩展方法来修剪到最大长度,所以你只需要调用一次lambda。

你会得到这样的结果

Func<IEnumerable<CommunicationDetails>, string> getFirstDtlTitle = ((dtls) => dtls.Where(x => x.CultureCode == culture).FirstOrDefault()?.Title ?? "");
communications.Select(c => new XElement("node",
                               new XAttribute("guid", Guid.NewGuid()),
                               new XAttribute("title", getFirstDtlTitle(c.CommunicationDetails).TrimToLength(40),
                               new XAttribute("isHidden", false))))

是的,您可以从stringIEnumerable<char>的事实中获益:

new string(Title.Take(40).ToArray()) //Take will take 40 first elements or as many as there are if less than 40.

string.Concat(Title.Take(40))

可能没有那么高性能,但是可读性更强,并且由于代码重复而更少出错。

如前所述,FisrtOrDefault().Title是等待发生的NullReferenceException

这看起来像是缺少字符串API的情况。编写一个方法,允许您传递一个字符串,并接受最多40个字符:

static class StringExtensions {
    public static SubstringUpTo(this string str, int len) {
        if (str == null) {
            return null;
        }
        if (len < 0) {
            throw new ArgumentException(nameof(len));
        }
        return len >= str.Length ? str : str.Substring(0, len);
    }
}

这可以避免第二次获得字符串:

new XAttribute(
    "title"
,   c.CommunicationDetails.FirstOrDefault(x => x.CultureCode == culture)
    ?.Title.SubstringUpTo(40)
)

注意使用?.运算符来处理没有需要的CultureCode项的情况,nullSubstringUpTo扩展方法内处理。

我认为最好的选择是提取标题逻辑分离方法。这将使程序更高效,更易读,更易测试。

communications.Select(c => new XElement("node",
    new XAttribute("guid", Guid.NewGuid()),
    new XAttribute("title", BuildTitle(c)),
    new XAttribute("isHidden", false))))

private string BuildTitle(CommuncationDetails c)
{
    var culturedDetails = c.CommunicationDetails.Where(x => x.CultureCode == culture).FirstOrDefault();
    if (culturedDetails == null || string.IsNullOrEmpty(culturedDetails.Title)) return string.Empty;
    return culturedDetails.Title.Substring(0, Math.Min(40, culturedDetails.Title.Length));
}