Tengo un método genérico y necesito garantizar que mi método devuelva nullable<T> (p. ej., la fuente es List<int> o List<int?> debe devolver int? ) y quiero devolver un valor nulo en lugar de predeterminado (p. ej., predeterminado de int es 0. en este caso quiero devolver nulo ). Puede ser posible agregar restricciones en el parámetro de tipo ( https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters ) pero con este enfoque debo tener 2 métodos (uno de ellos con restricción de estructura y otro con restricciones de clase )
mi método es:
public static T? ElementOrNull<T>(List<T> source, int? index) { if (source == null || index == null || source.Count <= index) return null; return source[index.Value]; } Intento Convert.ChangeType() y reflection( Activator.CreateInstance() and Activator.CreateInstance<T?>() ) pero no puedo resolver este problema.
Cualquier y todos los comentarios son apreciados. Gracias
Nota : Revisé todas las preguntas sobre los genéricos y su conversión en StackOverflow, pero no me ayudaron.
Las restricciones genéricas no son parte de la firma del método, pero el compilador aún necesita saber si T es un valor o un tipo de referencia para convertir null a T y manejar ? en T? correctamente. Pero puede ayudar al compilador usando parámetros restringidos opcionales de esta manera:
public class ReqStruct<T> where T : struct { } public class ReqClass<T> where T : class { } public static T? ElementOrNull<T>(List<T> source, int? index, ReqStruct<T> req = null) where T : struct { if (source == null || index == null || source.Count <= index) return null; return source[index.Value]; } public static T? ElementOrNull<T>(List<T> source, int? index, ReqClass<T> req = null) where T : class { if (source == null || index == null || source.Count <= index) return null; return source[index.Value]; }Y dado que los parámetros son opcionales, el uso se verá así:
var intOrNull = MethodHolder.ElementOrNull(new List<int> { 1 }, 5); // var is int? var objOrNull = MethodHolder.ElementOrNull(new List<object>(), 5); // var is object?Mi enfoque preferido para esto es usar un tipo de Opción/ Quizás personalizado. Es decir, una estructura con un valor genérico y un bool para describir si el valor es válido o no. Es decir, nunca use nulo, siempre use un Maybe para parámetros opcionales/valores devueltos:
public static Maybe<T> ElementOrNone<T>(List<T> source, Maybe<int> index) { if (source == null || !index.HasValue || source.Count <= index.Value) return Maybe<T>.None; return source[index.Value]; } Si bien las referencias anulables Nullable<T> y no anulables ayudan a evitar excepciones de referencias nulas, las encuentro deficientes al escribir código genérico, en parte debido al problema que está describiendo.
El uso de un tipo personalizado tiene la ventaja de un comportamiento coherente tanto para el valor como para los tipos de referencia, y puede permitir varias extensiones para facilitar el trabajo con valores, potencialmente incluso usando la sintaxis de consulta de linq para combinar varios valores. Una desventaja es que es un tipo personalizado, así que hay más para aprender.