Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extension method that accepts Expression<Func<T>> expression as parameter

I am using .NET4.5 and C# I fancied creating extension method that would allow me to pass property of object and if Id of that object is 0 then return null otherwise return that property value.

I could do it no problem with reflection so consider this more of training exercise and not me trying to solve the actual problem.

Currently extension method is sitting in static class looking like this:

    public static object GetNullIfNotSet(this WillAnswer answer, Expression<Func<WillAnswer>> expression)
    {
        if (answer.Id == 0) return null;
        return expression.Compile()();
    }

The way I want to be able to use it is following (answer is of type WillAnswer):

var emptyIfNewObject = answer.GetNullIfNotSet(o => o.HasBusinessAssets)

However it gives me compilation error:

Error 1 Delegate 'System.Func' does not take 1 arguments C:\hg\Website\Areas\Wills\ViewModel\Answers.cs 38 59 Website enter image description here

Which makes me frown since I don't think I am passing any arguments (am I?). Could please someone smarter than myself explain which of my expectations is wrong.

Just in case I wasn't clear I will reiterate. What I want is to be able to call var emptyIfNewObject = answer.GetNullIfNotSet(o => o.HasBusinessAssets) and get null if Id of answer is 0.

like image 691
Matas Vaitkevicius Avatar asked Oct 14 '15 09:10

Matas Vaitkevicius


2 Answers

No need for Expression at all, just use Func<WillAnswer, TProp>:

public static TProp GetNullIfNotSet<TProp>(this WillAnswer answer, Func<WillAnswer, TProp> func)
{
    if (answer.Id == 0) return default(TProp);
    return func(answer);
}

Please note, that this will not always return null but the default value (in case the property is a value-type).

Update (as per your request):

In order to be able to return null for all passed properties, the method signature was changed to return object instead:

public static object GetNullIfNotSet<TProp>(this WillAnswer answer, Func<WillAnswer, TProp> func)
{
    if (answer.Id == 0) return null;
    return func(answer);
}

But, you'll lose the benefits of generics and you'll end up with explicit casts to Nullable<T>:

var emptyIfNewObject = (bool?)answer.GetNullIfNotSet(o => o.HasBusinessAssets)

Which is less ideal.

like image 145
haim770 Avatar answered Nov 15 '22 18:11

haim770


It seems that you need a Func<WillAnswer, T> not an expression:

  public static T GetDefaultIfNotSet<T>(this WillAnswer answer, Func<WillAnswer, T> func) {
    if (null == answer)   
      throw new ArgumentNullException("answer");
    else if (null == func)   
      throw new ArgumentNullException("func");

    return answer.Id == 0 ? return default(T) : func(answer);
  }

EDIT: if you want to ensure null you can restrict generic T:

     public static T GetNullIfNotSet<T>(this WillAnswer answer, Func<WillAnswer, T> func) 
       where T: class { // no structs here
         if (null == answer)   
           throw new ArgumentNullException("answer");
         else if (null == func)   
           throw new ArgumentNullException("func");

         return answer.Id == 0 ? return null : func(answer);
     } 
like image 36
Dmitry Bychenko Avatar answered Nov 15 '22 19:11

Dmitry Bychenko