简体   繁体   中英

How to unpack an expression tree and check for null values

With reference to the 2 classes below, I am regularly writing LINQ statements like this..

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; }
}

My issues that I am having to constantly repeat my null checks on children navigation properties and I was wondering if there is a way I can use some kind of expression tree to extract the property values dynamically whilst checking for null values and if they didn't exist send back an empty string, something like the method below..

public class Country
{
    // Properties //

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

}

Usage:

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)
        });
}

If someone could provide a basic example that would be great as I don't have a whole lot of experience with expression tree's other than creating them.

Thanks.

Update -> would something like the following work?

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

I see no need for an expression. I would simply go for an extension-method like

    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;
              }
         }
   }

It works for all classes and you could implement further for other datatypes. The usage is the same as yours.

I think that you want something like this:

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);
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM