Метод расширения, который принимает выражение Expression <Func <T>> как параметр

Я использую .NET4.5 и C# Мне понравилось создание метода расширения, который позволил бы мне передать свойство объекта, и если Id этого объекта равен 0, тогда return null в противном случае вернет это значение свойства.

Я мог бы сделать это без проблем с отражением, поэтому рассмотрим это больше упражнений по обучению, а не меня, пытаясь решить реальную проблему.

В настоящее время метод расширения находится в классе static, который выглядит следующим образом:

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

Способ, которым я хочу использовать его, следующий (ответ имеет тип WillAnswer):

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

Однако это дает мне ошибку компиляции:

Ошибка 1 Делегат 'System.Func' не принимает 1 аргументы C:\hg\Website\Areas\Wills\ViewModel\Answers.cs 38 59 Веб-сайт введите описание изображения здесь

Что заставляет меня хмуриться, так как я не думаю, что передаю какие-либо аргументы (я?). Может ли кто-нибудь умнее меня объяснить, какие из моих ожиданий ошибочны.

На всякий случай я был неясен, я повторю. Я хочу, чтобы я мог позвонить   var emptyIfNewObject = answer.GetNullIfNotSet(o => o.HasBusinessAssets) и получите null, если Id of answer - 0.

Ответ 1

Нет необходимости в Expression вообще, просто используйте 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);
}

Обратите внимание, что это не всегда возвращает null, но значение по умолчанию (в случае, если свойство является значением типа).

Обновить (согласно вашему запросу):

Чтобы иметь возможность возвращать null для всех переданных свойств, сигнатура метода была изменена вместо return object:

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

Но вы потеряете преимущества дженериков, и в итоге вы получите явные приведения к Nullable<T>:

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

Что менее идеально.

Ответ 2

Кажется, вам нужно Func<WillAnswer, T> не выражение:

  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: если вы хотите обеспечить null, вы можете ограничить общий 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);
     }