El siguiente par de funciones intenta replicar el operador condicional nulo disponible en C# 6.0:
public static TResult Bind<T, TResult>(this T obj, Func<T, TResult> func) where T : class { return obj == null ? default(TResult) : func(obj); } public static TResult Bind<T, TResult>(this Nullable<T> obj, Func<T, TResult> func) where T : struct { return obj.HasValue ? func(obj.Value) : default(TResult); } La primera función está restringida a las clases y para un String s me permite escribir algo como:
var x = s.Bind(a => a.Substring(1)); La segunda función es donde me estoy metiendo en problemas. Por ejemplo, dado un int? number que me gustaría escribir:
var y = number.Bind(a => a + 1);Sin embargo, esto me da el siguiente error:
La llamada es ambigua entre los siguientes métodos o propiedades: 'BindingExtensions.Bind<T, TResult>(T, Func<T, TResult>)' y 'BindingExtensions.Bind<T, TResult>(T?, Func<T, TResult >)'
Supongo que esto tiene algo que ver con la interacción entre la inferencia de tipo de la función anónima y la resolución de sobrecarga del método. Si especifico el tipo de a como int , se compila perfectamente.
var y = number.Bind((int a) => a + 1);Sin embargo, esto es claramente menos que deseable. ¿Alguien puede decirme por qué el compilador cree que la llamada anterior para enlazar es ambigua u ofrecer una forma de solucionarlo? Sé que simplemente podría nombrar las dos funciones de manera diferente, pero ¿qué tan divertido es eso?
Las funciones sobrecargadas no se pueden desambiguar mediante restricciones de tipo (consulte " Restricciones genéricas, donde T: estructura y donde T: clase "). Cualquier tipo N que admite valores Nulables satisface N : T y N : Nullable<T> , requeridos por las definiciones de Bind anterior y posterior, respectivamente. Supongo que ese number es del tipo Nullable<int> o similar.
var x = s.Bind(a => a.Substring(1)); Esto no es ambiguo porque s es de tipo string y para todo T no string : Nullable<T> , por lo que solo se acepta la primera sobrecarga.
var y = number.Bind(a => a + 1); Esto es ambiguo porque el tipo de a => a + 1 puede inferirse como Func<int?,int?> o Func<int,int> . Si se deduce como Func<int?,int?> , se aplica la primera sobrecarga, y si se deduce como Func<int,int> se aplica la segunda sobrecarga.
var y = number.Bind((int a) => a + 1); Esto no es ambiguo si number es del tipo Nullable<int> , por ejemplo. Para la primera sobrecarga para todo T not T : Nullable<int> y T : int , por lo que no se aplica. Para la segunda sobrecarga, solo necesita T : int , que se satisface fácilmente con T = int .
Prueba esto:
public static TResult Bind<T, TResult>(this T? obj, Func<T?, TResult> func) where T : struct { return obj.HasValue ? func(obj.Value) : default(TResult); }