2015-10-14 2 views
10

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

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

В настоящее время метод расширения сидит в 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) 

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

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

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

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

+1

Как другие указали, вам не нужно выражение. Источником вашей ошибки является тот факт, что вы определили свою функцию неправильно.Вероятно, вы хотите что-то вроде Func (с объектом, возвращающим тип). –

+1

назовите его так: 'answer.GetNullIfNotSet (() => (((Func ) (() => answer.HasBusinessAssets))()));' какой беспорядок! вернитесь к ответу haim770 :-) –

+0

Если у вас есть доступ к объекту, к которому вы обращаетесь к свойству, когда вы вызываете метод, который вы выполняете, поскольку это расширение самого объекта, то почему бы просто не передать свойство вместо 'Func'? – user2697817

ответ

14

Нет необходимости в 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 но значение по умолчанию (в случае, если свойство имеет значение типа).

Update (согласно вашему запросу):

Для того, чтобы иметь возможность вернуть null для всех передаваемых свойств, метод подпись была изменена, чтобы вернуться 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) 

Который менее идеален.

+0

Отличный ответ, но как я могу его вернуть? –

+0

Чтобы всегда возвращать 'null', компилятор должен убедиться, что переданное свойство' x => x.SomeProp' является ссылочным типом. Это можно сделать, добавив общее ограничение, но это означает, что вы не сможете вернуть 'x => x.SomeInt' (например). Это то, что вам нужно? – haim770

+0

Не могли бы вы сделать небольшую алетерацию в ответ вместо 'TProp' return' object', это позволяет вернуть пустой публичный статический объект GetNullIfNotSet (этот ответ WillAnswer, Func func) { if (ответ. Id == 0) return null; return func (ответ); } ' –

7

кажется, что вам нужно 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); 
    } 
+0

Я бы также предложил переименовать имя метода в нечто вроде 'GetDefaultIfNotSet', потому что семантика изменилась - невозможно вернуть значение« null »для свойства' bool'. –

+0

@ Серый Колодий: Благодарю вас! Я отредактировал ответ: «GetDefaultIfNotSet» - гораздо лучшее имя. –

+0

@SergeyKolodiy, но мне нужен этот нуль, вот в чем суть вопроса –

Смежные вопросы