2010-12-27 17 views
29

¿Puedo devolver una referencia a un valor doble, por ejemplo?¿Es posible devolver una referencia a una variable en C#?

Esto es lo que quiero hacer:

ref double GetElement() 
{ 
    ...... 
    // Calculate x,y,z 
    return ref doubleArray[x,y,z]; 
} 

Para utilizar de esta manera

void func() 
{ 
    GetElement()=5.0; 
} 

Es como volver un doble puntero en C++ ... sé que la forma en que escribió que está mal ... pero ¿hay una forma correcta de hacerlo?

+0

qué quiere asignar el elemento a la matriz o obtener su valor? ¿Desea una función que lea algo o escriba algo? – Axarydax

+0

Quiero asignar un valor en la función de llamada .. – Betamoo

+0

No solo no puede hacer esto, está tratando de devolver una referencia a una instancia de un tipo de valor. Ni siquiera sé qué significaría eso. –

Respuesta

6

Valor los tipos en C# siempre pasan por valor. Los objetos siempre tienen su referencia aprobada por valor. Esto cambia en el código "inseguro" como señala Axarydax.

La manera más fácil y segura de evitar esta restricción es asegurarse de que su doble esté conectada a un objeto de alguna manera.

public class MyObjectWithADouble { 
    public double Element {get; set;} // property is optional, but preferred. 
} 

... 
var obj = new MyObjectWithADouble(); 
obj.Element = 5.0 

También quiero destacar que estoy un poco confundido acerca de cómo se anticipa que la asignación de un doble con una matriz tridimensional. Es posible que desee aclarar lo que está buscando.

Creo que entiendo un poco mejor lo que está pasando por ahora. Desea devolver la ubicación del valor en una matriz determinada y luego puede cambiar el valor en esa ubicación. Este patrón rompe algunos de los paradigmas esperados de C#, por lo que sugiero considerar otras formas de lograr lo que estás buscando. Pero si realmente tiene sentido hacerlo, lo haría algo más parecido a esto:

public class 3dArrayLocation {public int X; public int Y; public int Z;} 

... 

public 3dArrayLocation GetElementLocation(...) 
{ 
    // calculate x, y, and z 
    return new 3dArrayLocation {X = x, Y = y, Z = z} 
} 

... 

var location = GetElementLocation(...); 
doubleArray[location.X, location.Y, location.Z] = 5.0; 
+0

No se preocupe, la matriz no tiene 3 dimensiones sino 8 dimensiones ... Algo de aprendizaje automático con Q-Learning necesita eso :) – Betamoo

+1

@Betamoo: suena como todo tipo de diversión. Ver mi edición – StriplingWarrior

8

No, esto no es posible en C#. Solo puede pasar parámetros por referencia.

Sin embargo, se puede lograr el mismo resultado con una propiedad:

double Element 
{ 
    get { return doubleArray[x,y,z]; } 
    set { doubleArray[x,y,z] = value; } 
} 

void func() 
{ 
    Element = 5.0; 
} 
6

Usted podía hacerlo en unsafe code y tener un método que devuelve un puntero a doble:

unsafe double* GetElementP(){ 
... 
} 
+0

Aunque esto es posible, no lo recomendaría ...probablemente haya mejores formas de resolver el problema, pero el OP necesita dar más detalles sobre lo que quiere hacer –

+0

Tendría que arreglar la matriz en su lugar para que el recolector de basura no la mueva. –

+1

@Eric: Sé que esto podría ser un poco fuera de tema, pero sería terriblemente agradable si alguien blogueara sobre cómo el mapa 'interior_ptr' y' pin_ptr' de C++/CLI en el sistema tipo CLR, cómo se comparan las variables punteadas de C#, y si hay algún C# equivalente para los punteros C++/CLI. –

1

Después de pensar un poco, ¿por qué no envía el valor que se debe ajustar en la función como esta:

void SetElement(double value) 
{ 
    ...... 
    // Calculate x,y,z 
    doubleArray[x,y,z]=value; 
} 

y utilizarla:

void func() 
{ 
    SetElement(5.0); 
} 

Sin embargo, todavía voy a elegir una de sus votos respuestas ...

40

updat E: La característica deseada es ahora compatible con C# 7.


El sistema de tipos de CLR no apoyar métodos REF-volver, y he escrito un prototipo experimental del compilador de C#, que es compatible con la función que desea. (El prototipo también implementa variables locales ref-tipadas, pero los campos ref-typed son ilegales en el sistema de tipo CLR.)

Ha accedido exactamente a la sintaxis que elegí para el prototipo, lo que significa que las grandes mentes piensan igual , o que los tontos nunca difieren.

Aunque el prototipo funciona muy bien, es muy poco probable que esto haga que la barra se convierta en una característica de la próxima versión del lenguaje C#. Muy pocos clientes quieren esta característica, es bastante costosa de implementar, tenemos una lista siempre y cuando su brazo de características más importantes, y hay otras maneras de hacer que este tipo de cosas funcionen sin agregar esta complejidad al sistema de tipos. Estos son todos grandes "puntos en contra" de hacer la función.

Por ejemplo, usted podría hacer un par de delegados:

struct Ref<T> 
{ 
    private readonly Func<T> getter; 
    private readonly Action<T> setter; 
    public Ref(Func<T> getter, Action<T> setter) 
    { 
     this.getter = getter; 
     this.setter = setter; 
    } 
    public T Value { get { return getter(); } set { setter(value); } } 
} 

var arr = new int[10]; 
var myref = new Ref<int>(()=>arr[1], x=>arr[1]=x); 
myref.Value = 10; 
Console.WriteLine(myref.Value); 

Eso es considerablemente más lento que la misma característica implementada con rendimientos árbitro, pero la ventaja es que se puede hacer una Ref<T> en lugares donde ref es ilegal. Por ejemplo, puede almacenar Ref<T> en un campo, que no puede hacer con un método de devolución de referencia.

Si usted tiene un escenario realmente impresionante convincente de por qué se necesita métodos REF-volver, me amor oír hablar de eso. Cuantos más escenarios del mundo real tengamos, más probable es que dicha característica se implemente en una versión futura hipotética del idioma.

Ver preguntas También relacionado:

Can I use a reference inside a C# function like C++?

Why doesn't C# support the return of references?

y mi blog sobre el tema:

http://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/

+0

Tengo un escenario, que dudo califica como impresionante o convincente, pero me topa con una y otra vez: una clase que expone una estructura como una propiedad. Si solo se pudiera admitir 'Class.Struct.Property = value', sería posible actualizar ese valor de manera eficiente. En este caso, debe usar 'Class.Struct = new Struct {Property = value}' o agregar propiedades redundantes de ayuda a 'Class'. Incluso 'Ref ' no resuelve este problema. –

+0

@Rick: esa es otra razón por la cual las estructuras mutables son una peor práctica. Si quiere mutar una parte de una instancia particular de una estructura, entonces la está tratando como un tipo de referencia; convertirlo en un tipo de referencia en primer lugar. –

+6

Estoy de acuerdo conceptualmente, pero las estructuras mutables que parecen tipos de referencia son esenciales para la eficiencia. Si asignar/liberar un millón de instancias de referencia era tan rápido como un millón de estructuras, ¡no sería un problema! –

Cuestiones relacionadas