说我有三元手术:
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");
但那很难看。有没有办法重新处理这个我不必打包和取消包装返回值的地方?我对扩展/泛型非常陌生,所以如果这很简单,请原谅我。
答案 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";