programacion - sobrecarga de metodos c# pdf
Método de sobrecarga de valores de retorno (10)
¿Has pensado en usar genéricos para devolver el tipo correcto?
public T SomeFunction<T>()
{
return T
}
int x = SomeFunction<int>();
string y = SomeFunction<string>();
Nota: este código no ha sido probado
Esta pregunta ya tiene una respuesta aquí:
En C # tengo que ser capaz de definir un método, pero debe devolver uno o dos tipos de retorno. El compilador me da un error cuando intento hacerlo, pero ¿por qué no es lo suficientemente inteligente como para saber a qué método debo llamar?
int x = FunctionReturnsIntOrString();
¿Por qué el compilador me impide tener dos funciones con diferentes tipos de retorno?
Creo que quieres reconsiderar seriamente lo que estás haciendo y cómo, pero PUEDES hacer esto:
int i = FunctionReturnsIntOrString<int>();
string j = FunctionReturnsIntOrString<string>();
implementándolo de esta manera:
private T FunctionReturnsIntOrString<T>()
{
int val = 1;
if (typeof(T) == typeof(string) || typeof(T) == typeof(int))
{
return (T)(object)val;
}
else
{
throw new ArgumentException("or some other exception type");
}
}
Pero hay tantas razones para no hacerlo.
Desde el último párrafo de la sección 1.6.6 de la especificación del lenguaje C # 3.0 :
La firma de un método debe ser única en la clase en la que se declara el método. La firma de un método consiste en el nombre del método, el número de parámetros de tipo y el número, los modificadores y los tipos de sus parámetros. La firma de un método no incluye el tipo de retorno.
En IL, dos métodos pueden diferir solo por el tipo de retorno, pero fuera de la reflexión no hay manera de llamar a un método que difiera solo del tipo de retorno.
El tipo de retorno no es parte de la firma del método, solo el nombre y los tipos de parámetros. Debido a esto, no puede tener dos métodos que solo difieran según el tipo de retorno. Una forma de evitar esto sería que su método devuelva un objeto, luego el código de llamada debe convertirlo en un int o en una cadena.
Sin embargo, podría ser mejor crear dos métodos diferentes, o crear una clase para devolver desde el método que puede contener un int o una cadena.
En C # no hay tipos de retorno de overridin, IL admite ese tipo de anulación, pero C # no ... todavía.
Es posible obtener la sintaxis mostrada en la pregunta, pero debes involucrarte en una buena cantidad de inteligencia para llegar allí.
Vamos a configurar el problema un poco más concretamente. El punto clave aquí, creo, es la sintaxis. Queremos esto:
int intValue = GetData();
string stringValue = GetData();
DateTime[] dateTimeArrayValue = GetData();
Sin embargo, no queremos que esto funcione:
double doubleValue = GetData();
DateTime? nullableDateTimeValue = GetData();
Para lograr esto, tenemos que usar un objeto intermediario en el valor de retorno de GetData()
, cuya definición se ve así:
public class Data
{
public int IntData { get; set; }
public string StringData { get; set; }
public DateTime[] DataTimeArrayData { get; set; }
public MultiReturnValueHelper<int, string, DateTime[]> GetData()
{
return new MultiReturnValueHelper<int, string, DateTime[]>(
this.IntData,
this.StringData,
this.DataTimeArrayData);
}
}
Su implementación, por supuesto, sería bastante diferente, pero esto servirá. Ahora definamos MultiReturnValueHelper
.
public class MultiReturnValueHelper<T1, T2, T3> : Tuple<T1, T2, T3>
{
internal MultiReturnValueHelper(T1 item1, T2 item2, T3 item3)
: base(item1, item2, item3)
{
}
public static implicit operator T1(MultiReturnValueHelper<T1, T2, T3> source)
{
return source.Item1;
}
public static implicit operator T2(MultiReturnValueHelper<T1, T2, T3> source)
{
return source.Item2;
}
public static implicit operator T3(MultiReturnValueHelper<T1, T2, T3> source)
{
return source.Item3;
}
}
Repita esta definición para T1
, T2
, T3
, etc. para el caso genérico.
También puede vincular el ayudante del valor de retorno muy de cerca a la clase o método que lo devuelve, lo que le permite crear este mismo tipo de efecto para los indexadores, donde puede obtener y asignar un conjunto discreto de tipos. Ahí es donde lo he encontrado más útil.
Otra aplicación es habilitar la sintaxis como la siguiente:
data["Hello"] = "World";
data["infamy"] = new DateTime(1941, 12, 7);
data[42] = "Life, the universe, and everything";
El mecanismo preciso para lograr esta sintaxis se deja como un ejercicio para el lector.
Para una solución de propósito más general para este problema (que es, creo, lo mismo que un problema sindical discriminado), vea mi respuesta a esa pregunta .
Las funciones que difieren solo con los valores de retorno no califican para la sobrecarga.
int x = FunctionReturnsIntOrString();
double y = FunctionReturnsIntOrString();
En el caso anterior, el compilador puede identificar las funciones correctas pero considerar los casos en los que no se especifican valores de retorno, es ambiguo.
FunctionReturnsIntOrString(); //int version
FunctionReturnsIntOrString(); //double version
El compilador no puede resolver los métodos sobrecargados aquí.
Porque a veces realmente no se puede decir cuál debería usar (su ejemplo podría, pero no todos los casos son tan claros):
void SomeMethod(int x) { ... }
void SomeMethod(string x) { ... }
En este contexto, si llama a SomeMethod(FunctionReturnsIntOrString())
¿qué debe hacer el compilador?
Si bien puede ser obvio en este escenario particular, hay muchos escenarios en los que esto no es obvio. Vamos a tomar la siguiente API para un ejemplo
class Bar {
public static int Foo();
public static string Foo();
}
Simplemente no es posible que el compilador sepa a quién llama Foo en los siguientes escenarios
void Ambiguous() {
Bar.Foo();
object o = Bar.Foo();
Dog d = (Dog)(Bar.Foo());
var x = Bar.Foo();
Console.WriteLine(Bar.Foo());
}
Estas son sólo algunas muestras rápidas. Más falsos y falsos problemas seguramente existen.
Tampoco es necesario que asigne un valor a un método llamado. Por ejemplo:
int FunctionReturnsIntOrString() {return 0;}
string FunctionReturnsIntOrString() {return "some string";}
//some code
//...
int integer = FunctionReturnsIntOrString(); //It probably could have figured this one out
FunctionReturnsIntOrString(); //this is valid, which method would it call?