扩展隐藏三元运算符

时间:2014-03-13 20:39:24

标签: c# generics reflection extension-methods

说我有三元手术:

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

但那很难看。有没有办法重新处理这个我不必打包和取消包装返回值的地方?我对扩展/泛型非常陌生,所以如果这很简单,请原谅我。

3 个答案:

答案 0 :(得分: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";

答案 1 :(得分: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());

答案 2 :(得分:1)

不需要扩展方法的替代答案:

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