2009-04-19 14 views

Respuesta

4

Out también se puede utilizar para operaciones que pueden fallar (normalmente se encuentran en métodos que inician Try *).

E.g. TryParse devolverá un bool que indica éxito/falla al usar el valor de salida como resultado. Esto evita tener que lanzar excepciones.

0

Si el objeto puede ser nulo. No hay necesidad de instatar luego.

3

Has encontrado exactamente la razón por la que debería usarse. Para reducir la complejidad del código.

if (TryGetValue(myObj)) 
{ 
    [...] 
} 

es más ordenada que

Result tryGetValueResult = TryGetValue(); 
if (tryGetValueResult.Found) 
{ 
    [...] 
} 

También puede ahorrar en la basura cuando el resultado tiene que ser un tipo de referencia.

+0

Aquí hay un hilo relacionado: http://stackoverflow.com/questions/134063/why-are-out-parameters-in-net-a-bad-idea – razlebe

+0

Hay una línea delgada entre menos cantidad de código y extensibilidad y elegancia Digamos que si hay más de dos params fuera, sería más prudente tener como tipo de retorno los efectos secundarios – Ramesh

3

Si no hay una razón general para encapsular los múltiples valores juntos, aparte de esta llamada, la creación de un tipo separado probablemente sea exagerada.

Por otro lado, si tiene múltiples parámetros de salida y un valor de retorno que lógicamente pertenecen todos juntos (por ejemplo, nombre, apellido, número de teléfono), entonces tendría sentido crear un tipo apropiado (por ejemplo, "Contacto ") y devolver eso.

Una alternativa para la opción TryGetValue es utilizar tipos de valores que se pueden anular, si el valor en cuestión es un tipo de valor. Por ejemplo, int.TryParse podría haber tenido una firma de:

int? TryParse(string text) 

(con una sobrecarga de tomar una IFormatProvider por supuesto).

3

Son útiles en la (rara) situación en la que necesita devolver un valor desde un constructor. Por ejemplo, el constructor Mutex tiene un parámetro boolean out que está configurado para indicar si se creó un Mutex nuevo o si ya existe un mutex existente con un nombre.

0

Yo votaría por usar el tipo de devolución. Aunque C# no es un lenguaje funcional, creo que es bueno apuntar a un estilo de programación funcional. No por pureza académica, sino por los beneficios pragmáticos, donde el comportamiento de cada función no es misterioso, sin efectos secundarios.

+1

y misterioso implica que la función hace algo que no esperabas. Si pasa algo en una posición de salida, ¿no es exactamente lo que esperaba que hiciera? –

0

Si espera que su función simplemente devuelva una referencia a un objeto que sale o cree un nuevo objeto, entonces solo debería usarse el parámetro out.

-3

Me gusta reservar los valores de devolución para los indicadores de éxito.Ya sea simple verdadero/falso para el éxito o algo más complejo como 0 para el éxito y otros valores que indican cuál fue el error.

Esto significa que un programador puede probar el éxito en cada función que escriba. (Por supuesto, no todos, pero la podía)

Esto requiere entonces fuera parámetros para recuperar los valores de la función.

+1

-1 - En .NET, debería preferir excepciones para devolver códigos en el caso general. Ocasionalmente puede haber una función que espera que falle una proporción razonable de tiempo, en cuyo caso un código de retorno sería apropiado; sin embargo, este no es el caso habitual. –

2

La palabra clave out aplica un par de cosas mediante el compilador ..
El llamante no tiene que inicializar el parámetro. El destinatario no puede leer el parámetro, pero tiene que escribir antes de salir del método.

más importante hace el intento visible como la persona que llama tiene que especificar la palabra clave a cabo al realizar una llamada a un método

Se puede utilizar cuando se necesidad de devolver varios valores de un método (sin rellenarlos y destuflarlos de un objeto []). (La sección que adora devolver bSuccess de cada función le encantaría la palabra clave out.)
En el ejemplo que publicó ... El valor de retorno primario de TryParse es el éxito de la operación de análisis. Entonces ese es su valor de retorno, pero la necesidad subsiguiente más probable sería obtener el objeto analizado si tuviera éxito. Entonces, en lugar de hacer que todos los que llaman hagan ese paso, TryParse le ahorra la molestia entregándolo como un param out ... ya que ya lo hizo como parte de la verificación de CanParse.

1

Los parámetros de salida generalmente son del lado frágil. Yendo más allá del ejemplo, y mirando el problema en general: el libro de Bill Wagner "Más efectivo C#" describe un enfoque bastante inteligente para esto, también se describe en detalle here.

El siguiente código funcionaría en esta instancia.

public class Tuple<T1,T2> 
{ 
    public T1 First {get;private set;} 
    public T2 Second {get; private set;} 
    Tuple(T1 first, T2 second) 
    { 
    First = first; 
    Second = second; 
    } 
} 


using ComplexPair = Tuple<bool,object>; 

public class SomeOtherClass 
{ 
    public ComplexPair GetComplexType() 
    { 
    ... 
    return new ComplexPair(true, new object); 

    } 
} 
0

En mi openion ambos tienen razón, sin embargo, encuentran regresan un tipo complejo más elegante sobre todo si se trata de un tipo genérico

ReturnType<T> 

esto da más información acerca de lo que puede esperar el valor será, por lo que no adivina el tipo de valor original y el fundido.

1

Sería mejor utilizar algo así como un tipo de opción como contenedor para los tipos de devolución que podrían estar ausentes. Estos son frecuentes en la mayoría de los lenguajes funcionales como Scala. Útil para el caso en el que solo te importa si algo tiene éxito o falla, y no te importa por qué. p.ej. Analizando enteros.

int num; // mutable = bugprone 
if (!int.TryParse(str, out num)) // branching = complexity 
    num = someDefault; 

Utilizando el tipo de opción, se podría definir un analizador int que se clausura la fealdad mutable y devuelve una opción limpia. esto reduce su complejidad teniendo esto si en UN SOLO LUGAR. evita la duplicación y la mutación.

uso
public Option<int> IntParse(string str) { 
    int num; // mutable 
    if (!int.TryParse(str, out num)) 
     return Option.None<int>(); 
    else 
     return Option.Some<int>(num); 
    } 

en otra parte:

int result = IntParse(someString).GetOrElse(defaultValue); 

Como se puede ver esto da lugar a un patrón de uso mensurable menos complejo, ya que la ramificación se ha ocultado.

Alternativamente, si su función tiene que devolver dos cosas, existe la posibilidad de que:

  • la función es demasiado complejo y debería dividirse hacia arriba (hacer una cosa bien!), O
  • El los valores de devolución están estrechamente relacionados y deben estar unidos en un nuevo tipo

¡Cosas para pensar!

Cuestiones relacionadas