2014-03-13 4 views
2

Скажет, у меня есть троичная операция:Расширения Скрыть оператор троичного

db.Scanners.FirstOrDefault(s => s.ScannerID==24) != null 
     ? db.Scanners.FirstOrDefault(s => s.ScannerID==24).FriendlyName 
     : "N/A"; 

Я хотел написать расширение LINQ, чтобы скрыть операцию. Моя лучшая попытка:

public static object PropertyOrNull<T>(this T source, string property) 
{ 
    if (source == null || source.GetType().GetProperty(property) == null) 
     return null; 

    return source.GetType().GetProperty(property).GetValue(source, null); 
} 

, который я могу позвонить прямо сейчас с помощью:

(string)db.Scanners.FirstOrDefault(s => s.ScannerID == 24) 
      .PropertyOrNull("FriendlyName"); 

Но это довольно некрасиво. Есть ли способ переделать это, когда мне не нужно вставлять и отменять возвращаемое значение? Я довольно новичок в расширениях/дженериках, поэтому простите меня, если это просто.

+2

То есть а не расширение LINQ. Это просто расширение. LINQ - это просто набор методов расширения в пространстве имен 'System.Linq'. Вы не добавляете его туда, вы добавляете свое собственное расширение в другое место. – Servy

ответ

4

Вы можете сделать что-то подобное:

public static TProperty TryGetValue<T, TProperty>(
    this T source, 
    Func<T, TProperty> getter, 
    TProperty defaultValue = default(TProperty)) 
{ 
    if (source == null) 
     return defaultValue; 

    return getter(source); 
} 

Используйте его так:

db.Scanners.FirstOrDefault(s => s.ScannerID == 24) 
      .TryGetValue(s => s.FriendlyName, "N/A"); 

Этот подход намного быстрее, чем использование отражения, а также безопаснее, поскольку во время компиляции будет обнаружено недопустимое имя свойства. Он также строго типизирован, что означает, что вам не нужно приводить результат.

Другой подход, который не требует нового метода расширения является проектирование последовательности перед вызовом FirstOrDefault:

db.Scanners.Select(s => s.FriendlyName) 
      .FirstOrDefault() ?? "N/A"; 
+0

это потрясающе. Особенно с дополнительным значением defaultValue. Thankyou очень – Jonesopolis

2

Итак, прежде всего, вместо отражения вы должны просто принять делегата. Вы можете также использовать второй общий аргумент для обработки возврата фактического типа объекта:

public static TResult Use<T, TResult>(this T obj, Func<T, TResult> selector) 
    where TResult : class 
    where T : class 
{ 
    if (obj == null) 
     return null; 
    return selector(obj); 
} 

Вы можете назвать это так:

var str = something.Use(s => s.ToString()); 
1

Альтернативный ответ, который не нужен метод расширения:

var friendlyName = db.Scanners.Where(s => s.ScannerID == 24) 
        .Select(s => s.FriendlyName).FirstOrDefault() ?? "N/A"; 
+0

Это только вариант, если у вас есть 'IEnumerable' для начала. Если этот предмет не был частью последовательности, это не так возможно. – Servy

+0

Это справедливо. Я предположил, что OP специально пытался избежать двойного анти-шаблона FirstOrDefault, но вы правы, это предположение с моей стороны. – aquinas

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