Domanda

Say I have a ternary operation:

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

I wanted to write a LINQ extension to hide the operation. My best attempt is:

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

which I can call now via:

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

But that's pretty ugly. Is there a way to re-work this where I don't have to box and unbox the return value? I'm pretty new to extensions/generics, so forgive me if this is simple.

È stato utile?

Soluzione

You can do something like that:

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

Use it like that:

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

This approach is much faster than using reflection, and also safer, because an invalid property name would be detected at compile time. It is also strongly typed, which means you don't need to cast the result.

Another approach that doesn't require a new extension method is to project the sequence before calling FirstOrDefault:

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

Altri suggerimenti

So first off, rather than reflection you should simply accept a delegate. You can also use a second generic argument to handle returning the actual type of the object:

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

You can then call it like so:

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

Alternative answer that doesn't need an extension method:

var friendlyName = db.Scanners.Where(s => s.ScannerID == 24)
                     .Select(s => s.FriendlyName).FirstOrDefault() ?? "N/A";
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top