假设我有一个三元运算:
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");
但是那很难看。是否有一种方法来重新工作,我不需要框和打开返回值?我对扩展/泛型很陌生,所以如果这很简单,请原谅我。
你可以这样做:
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";
所以首先,你应该接受委托而不是反射。还可以使用第二个泛型参数来处理返回对象的实际类型:
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());
不需要扩展方法的备选答案:
var friendlyName = db.Scanners.Where(s => s.ScannerID == 24)
.Select(s => s.FriendlyName).FirstOrDefault() ?? "N/A";