from framework firstordefault first array c# linq syntax

framework - Deshabilitar de forma segura la llamada de FirstOrDefault en Linq c#



linq first c# (3)

Para mayor brevedad en mi código, me gustaría poder hacer lo siguiente: tener una colección, encontrar el primer elemento que coincida con una expresión lambda; si existe, devuelve el valor de una propiedad o función. Si no existe, devuelve nulo.

Ejemplos actualizados w. clases

Vamos a tener una colección de cosas

class Stuff { public int Id { get; set; } public string Value { get; set; } public DateTime? ExecutionTime { get; set; } }

Lo que busco es una forma de regresar bien cuando llame a este

var list = new Stuff[] { new Stuff() { Id = 1, Value = "label", ExecutionTime = DateTime.Now } }; // would return the value of ExecutionTime for the element in the list var ExistingTime = list.FirstOrDefault(s => s.Value.Contains("ab")).ExecutionTime; // would return null var NotExistingTime = list.FirstOrDefault(s => s.Value.Contains("zzz")).ExecutionTime;

¿Es posible con algunos linq-syntax-fu o tengo que verificar explícitamente el valor de retorno antes de continuar?

Ejemplo original w. instrumentos de cuerda

var stuff = {"I", "am", "many", "strings", "obviously"}; // would return "OBVIOUSLY" var UpperValueOfAString = stuff.FirstOrDefault(s => s.contains("bvi")).ToUpper(); // would return null var UpperValueOfAStringWannabe = stuff.FirstOrDefault(s => s.contains("unknown token")).ToUpper();

Comentario: No debería haber usado cadenas en mi ejemplo original, ya que desvía ligeramente la pregunta centrándola en el método ToUpper y la clase de cadena. Por favor considere el ejemplo actualizado


¿Por qué no simplemente hacer:

stuff.Where(s => s.contains("bvi")) .Select(s => s.ToUpper()) .FirstOrDefault()

Si tiene un "valor predeterminado no predeterminado", puede hacer:

stuff.Where(s => s.contains("bvi")) .Select(s => s.ToUpper()) .DefaultIfEmpty("Something Else") .First()


Me gusta esto como un método de extensión:

public static U SelectMaybe<T, U>(this T input, Func<T,U> func) { if (input != null) return func(input); else return default(U); }

Y uso:

var UpperValueOfAString = stuff.FirstOrDefault(s => s.Contains("bvi")).SelectMaybe(x => x.ToUpper()); var UpperValueOfAStringWannabe = stuff.FirstOrDefault(s => s.Contains("unknown token")).SelectMaybe(x => x.ToUpper());

Esto encadenará el valor predeterminado ( null en este caso, pero como es correcto para ese tipo), o llamará a la función relevante y devolverá eso.


Actualizar:

De acuerdo con la aclaración de la pregunta, no necesita ningún código adicional para lograr lo que desea. Simplemente use una cláusula where y una cláusula de proyección selecta:

var theString = stuff .Where(s => s.contains("unknown token")) .Select(s => s.ToUpper()) .FirstOrDefault(); Respuesta antigua

Como se sugirió en los comentarios ( y se hizo genérico en otra respuesta ), envuelva la llamada ToUpper en un método de extensión. Los métodos de extensión se reducen a la sintaxis del azúcar en torno a las llamadas a métodos estáticos, para que puedan manejar los nulos sin problemas.

static class StringExtensions { public static string PossiblyToUpper(this string s) { if (s != null) return s.ToUpper(); return null; } }

Tu llamada se convertiría en:

var upperValueOfAStringWannabe = stuff .FirstOrDefault(s => s.contains("unknown token")) .PossiblyToUpper();

Ahora es solo una discusión sobre si el método de extensión para admitir simplemente el código de estilo de una sola línea es más expresivo que las múltiples líneas: al final del día, expresar la intención del código es más importante que el aspecto del código.

Personalmente, creo que los métodos de extensión que manejan los nulos son confusos a primera vista, ya que se suavizan para parecerse a los métodos regulares.