如何解压缩表达式树并检查空值

本文关键字:检查 空值 表达式 解压缩 | 更新日期: 2023-09-27 17:57:29

参考下面的两个类,我经常编写这样的LINQ语句。。

using (var db = new DBContext())
{
    var result = db.Countries
        .Select(c => new
        {
            c.Name,
            c.Leader != null ? c.Leader.Title : String.Empty,
            c.Leader != null ? c.Leader.Firstname : String.Empty,
            c.Leader != null ? c.Leader.Lastname : String.Empty
        });
}
public class Country
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Leader Leader { get; set; }
}
public class Leader
{
    public string Title { get; set; }
    public string Firstname { get; set; }
    public string Lastname { get; set; }
}

我的问题是,我必须不断重复对子导航属性的null检查,我想知道是否有一种方法可以使用某种表达式树来动态提取属性值,同时检查null值,如果它们不存在,则返回一个空字符串,类似于下面的方法。。

public class Country
{
    // Properties //
    public string SafeGet(Expression<Func<Country, string>> fnc)
    {
        // Unpack fnc and check for null on each property?????
    }
}

用法:

using (var db = new DBContext())
{
    var result = db.Countries
        .Select(c => new
        {
            c.Name,
            c.SafeGet(l => l.Leader.Title),
            c.SafeGet(l => l.Leader.Firstname),
            c.SafeGet(l => l.Leader.Lastname)
        });
}

如果有人能提供一个基本的例子,那就太好了,因为除了创建表达式树之外,我对表达式树没有太多的经验。

谢谢。

更新->是否需要以下操作?

public string GetSafe(Expression<Func<Country, string>> fnc)
{
    var result = fnc.Compile().Invoke(this);
    return result ?? string.Empty;
}

如何解压缩表达式树并检查空值

我认为不需要表达式。我会简单地选择像这样的扩展方法

    public static class ModelExtensions
    {
         // special case for string, because default(string) != string.empty 
         public static string SafeGet<T>(this T obj, Func<T, string> selector)
         {
              try {
                  return selector(obj) ?? string.Empty;
              }
              catch(Exception){
                  return string.Empty;
              }
         }
   }

它适用于所有类,并且可以为其他数据类型进一步实现。用法与您的相同。

我想你想要这样的东西:

public static class ModelExtensions
{
    public static TResult SafeGet<TSource, TResult>(this TSource obj, System.Func<TSource, TResult> selector) where TResult : class
    {
        try
        {
            return selector(obj) ?? default(TResult);
        }
        catch(System.NullReferenceException e)
        {
            return default(TResult);
        }
    }
}