2010-01-29 14 views
9

Tengo una clase que es principalmente un contenedor para una gran matriz y algunas tareas domésticas asociadas. Tengo una función que toma un parámetro ref. Cuando paso una instancia de la clase a la función, quiero que se envíe la matriz.Pasar un lanzamiento explícito como un parámetro ref (C#)

Considere los moldes explícitos. Digamos que tengo alguna función que tiene un parámetro byte [] ref.

public void SomeFunction(ref byte[] someBytes); 

Y que tengo alguna clase con un molde explícito sobrecargado.

class SomeClass 
    { 
     byte[] someBytes; 
     public static explicit operator byte[](SomeClass someInstance) 
     { 
      return someInstance.someBytes; 
     } 
    } 

Ahora quiero llamar a la función con la clase como un parámetro

SomeClass someInstance = new SomeClass(); 
    SomeFunction(ref (byte[]) someInstance); 

El compilador se queja de "un ref o argumento a cabo deben ser una variable asignable". No estoy seguro de si estoy fallando en dar masajes al compilador correctamente o si realmente no puedes hacer eso.

me considera un valor de retorno de la propiedad o función, pero no se puede pasar por los ref (y después de educar a mí mismo veo por qué ...)

preferiría no hacer la matriz un campo público , pero eso satisface al compilador. Yo supongo tan sólo pudiera crear una variable local para hacer referencia a la matriz con, pero eso es una línea adicional de código antes y después de cada llamada a la función ...

EDIT: podría valer la pena señalar que fue escrito por algunaFuncion un tercero y no tengo acceso para cambiarlo. Peor aún, no creo que su parámetro realmente deba ser ref ...

Respuesta

9

Una conversión no es una variable asignable; estás pasando un valor de retorno de tu operador de lanzamiento explícito.

Se puede crear una variable que contiene el valor adecuadamente fundido antes de pasarlo como un ref:

SomeClass someInstance = new SomeClass(); 
byte[] someBytes = (byte[])someInstance; 
SomeFunction(ref someBytes); 

Tenga en cuenta que ahora es la variable someBytes que puede ser reasignado. Deberá tomar medidas para reasignar someInstance.someBytes de alguna manera después de la llamada al SomeFunction si desea que se reasigne el valor interno de someInstance.

+0

Así resulta que la solución práctica sería ser un campo público o un método corto cuyo único propósito es encubrir la creación de una variable local para pasar. Yo algunos medicamentos genéricos más excavación podría ayudar , también. – ajs410

+0

Correcto, un setter simple sería suficiente para actualizar alguna instancia. Como alternativa, puede crear una interfaz que SomeFunction tome como argumento y SomeInstance implemente e implemente su lógica a través de esa interfaz. –

1

No puede hacer eso, primero debe materializar el resultado de convertir su objeto en una variable.

considere el siguiente código, si lo que pide se le permitió:

public void SomeFunction(ref byte[] someBytes) 
{ 
    someBytes = new byte[] { 1, 2, 3 }; 
} 

SomeClass someInstance = new SomeClass(); 
SomeFunction(ref (byte[]) someInstance); 
// uh-oh, what is "someInstance" now? 

¿Por qué es el argumento marcado "ref", lo que es un problema que estamos tratando de resolver aquí?

+0

El argumento se marca con una referencia probable debido a que el desarrollador original de terceros estaba transfiriendo una biblioteca de C++ a .NET. El problema que estoy tratando de resolver es bailar alrededor de la referencia sin hacer que someBytes sea un campo público o crear la variable local. Elegí el "molde explícito" porque sabía que los campos de limpieza se perderían. Esperaba que alguna instancia pasara la referencia a algunos Bytes junto con SomeFunction. No es muy diferente de usar un campo público, pero forzar expulsiones explícitas lo haría menos propenso al abuso. – ajs410

+1

Bueno, los parámetros "ref" y "out" requieren una variable de respaldo, realmente no hay forma de evitar eso, así que solo tienes que definir la variable como ya has descubierto. Por supuesto, podrías hacer shim-methods en una clase propia para hacer esa traducción por ti, y llamar a esos métodos, que a su vez harían el reparto, almacenarían en una variable y llamarían a los métodos reales, pero eso podría tampoco será una buena solución. –

+0

La solución final en realidad implica crear una copia local de la referencia al byte [] y ref'ing esa copia local. Esto está violando técnicamente el punto de referencia, pero estoy bastante seguro de que el programador de terceros pensó que ref en C# era lo mismo que & en C++ y eso no es cierto. – ajs410

1

El alcance de los valores que se pueden usar como un parámetro de referencia en C# está limitado por lo que permite el CLR. Se especifica en la especificación CLI en las secciones 12.4.1.5.2 y 12.1.6.1 e incluye

  • argumento del método actual
  • variable local
  • Campo miembro de un objeto
  • Campo Estático
  • elemento de matriz

Un molde no se ajusta a ninguna de estos y, por lo tanto, no se pueden usar como valor ref. Deberá asignarlo a un valor como local antes de pasarlo por referencia.

+0

¡Gracias por la referencia a la especificación! No llegué a C# por un tiempo, así que de alguna manera esto fue más una cuestión académica ya que exploré completamente las diversas características del lenguaje ... y seguro que hay muchas. – ajs410

0

¿Realmente tiene que emitir el parámetro ref? En mi caso, algo así funciona bien.

byte[] someInstance = (byte[])new SomeClass(); 
SomeFunction(ref someInstance); 
Cuestiones relacionadas