Algo de fundamentos teóricos

25/10/2008 - 14:24 por Hugo Nugra | Informe spam
Amigos.

Tengo dos objetos de una misma clase: ObjA y ObjB.

Existe una serie de otros objetos que "apuntan" a ObjA, ineractúan con sus
propiedades y ejecutan sus métodos. Sucede que por alguna razón, necesito
que todo lo que apunta a ObjA, ahora apunte aObjB.

Si intento con

ObjA = ObjB

todas las referencias que existían hacia ObjA, ahora apuntan a un null
(nulo), con los consabidos inconvenientes.

Si en concepto ObjA y ObjB son solamente referencias a una dirección de
memoria, quisiera saber si existe alguna manera de decirle al programa que
ahora la dirección de memoria de ObjA es la dirección de memoria de ObjB.

Este requerimirnto se pone de manifiesto cuando se instancian formularios
que han sido creados utilizando el diseñador de visual estudio, utilizando un
objeto de tipo DataSet; pues el generador de código crea una instancia del
tipo DataSet y DataBindings que lo apuntan en cada campo de datos. El
problema aparece cuando se necesita presentar el formulario pero con un
DataSet que ya existe y que ya está poblado de datos. Vendría bien una
solución como la que he planteado anteriormente.

Por cierto, yo he solucionado el problema de la presentación del formulario,
pero no de la manera que me gustaría.

Si alguien tiene algún cometario a respecto, de antemano, ¡Gracias!.

Preguntas similare

Leer las respuestas

#16 Paco Ferre
28/10/2008 - 12:12 | Informe spam
Hola.

Una puntualización a la frase de Alfredo al final, que es correcta.

ObjA = ObjB;

Lo que haces es que la variable de tipo puntero de ObjA apunte a la
variable que está siendo apuntada por la variable de tipo puntero ObjB.



Usando el concepto "objeto" como el espacio de memoria reservado para
una instancia de una clase la frase podría quedar un poco más clara.

ObjA = ObjB;

Lo que haces es que la variable de tipo puntero de ObjA apunte al
objeto que está siendo apuntado por la variable de tipo puntero ObjB.

De forma sencilla, una variable de tipo puntero no es más que un
"numeríto" que dá una posición de memoria. Se dice entonces que la
variable apunta a ese objeto.
Gracias a esto tenemos herencia, interfaces...

¿Qué pasa entonces con el espacio de memoria al que apuntaba ObjA (si
es que no era null)?
Pues que si no existe ninguna otra variable tipo puntero que apunte a
la misma posición de memoria el recolector de basura (cuando tiene un
rato libre, jeje) libera el espacio de memoria para su posterior uso.


Sobre otro post de Pedro:

public void PresentarDatos(MiDataSet otrosDatos)
{
// En este punto me gustaría saber si puedo hacer
// que todo lo que hacía referencia a miDataSet,
// ahora hiciera referencia a otrosDatos.
}
}



No estoy seguro pero lo unico que podría decirte es que pruebes poniendo
"ref" (por referencia). A veces hasta las referencias hay que pasarlas
por referencia :)

public void PresentarDatos(ref MiDataSet otrosDatos)

y al llamarlo

elDataset=new MiDataSet();

PresentarDatos(ref elDataset);



Jeje, eso de probar a ver qué pasa...

Lo primero que no hay que olvidar es que una aplicación "trabaja" con
bits, que se agrupan en bytes y a su vez en conjuntos de bytes que
están en la memoria del ordenador.

Tenemos dos tipos de variables (los delegates los dejo aparte) para el
"uso diario".
- Los que llaman Value Types. Variables tipo numérico.
int numero = 2;
double otronumero = 20;

¿Qué es esto?, en términos prácticos "numero" es una palabra que nos
permite almacenar un 2 sabiendo perfectamente que "numero" y
"otronumero" no comparten la misma posición de memoria y por tanto no
puedo modificar "numero" a través de "otronumero" y viceversa.

((

En C standard-de-toda-la-vida podíamos saber el valor de la posición
de memoria de la variable "numero" escribiendo
int *posiciondenumro = №

"posiciondenumero" es un puntero a entero.
Y podríamos modificar "numero" a través de él.
*posiciondenumero = 4;

jojo, y si hacíamos:
posiciondenumero += 1; (salta a la siguiente posición de memoria, 4
bytes hacia delante si int ocupaba 4 bytes)
*posiciondenumero = 8; (a saber donde habíamos escrito el 8 este...
puede que sobre el primer cacho de 8 bytes (double) de "otronumero"
según el compilador)

))


El lenguaje nos permite tratar a las variables-tipo-numero como
objetos, pero no es lo mismo.
numero.ToString() o hasta (3 + 5).ToString()

¿Qué pasa cuando "enviamos" una variable tipo numero a una funcion?

Consideremos el ejemplo.

void Funcion(int parametro)
{
parametro = 20;
}
...
{
int numero = 5;

Funcion(valor);
Funcion(40);
}

Pues lo que imaginamos, "parametro" ocupa una posición de memoria
distinta de "numero" por lo que el 20 no es almacenado en la posición
de memoria de "numero".
O sea, que en el primer caso, el valor 5 se copia a la posición de
memoria de "parametro", así como el valor 40.

¿Para qué sirve ref?

void Funcion(ref int parametro)
{
parametro = 20;
}
...
{
int numero = 5;

Funcion(ref valor);
Funcion(ref 40); // ERROR.
Funcion(40); // ERROR.
}

ref le indica al compilador que queremos que "parametro" ocupe la
misma posicion de memoria que "numero" por lo que las modificaciones
en "parametro" obviamente modifican "numero".

No podemos enviar 40 porque no es una variable.

Y hasta aquí van los numeritos.



- Los otros, no me acuerdo del nombre en inglés, que son "los-que-se-
usan-para-los-objetos", jeje. Variables tipo puntero.

class MiClase
{
public int datoA = 3; // Esto es un ejemplo, no se hace,
"public" para variables es malo.
public int datoB = 5;
}
...
{
MiClase clase1 = new MiClase();
MiClase clase2 = new MiClase();
}

¿Cómo funciona?, vamos a simplificar mucho, pero mucho mucho mucho.
MiClase clase1 = new MiClase();
Imaginamos que "clase1" son int, y que lo que se hace es:

- Reservo un espacio de memoria de 8 bytes para MiClase porque
necesito almacenar los valores de las variables (datoA y datoB).
- La "posición fisica" de ese espacio de memoria, digamos 16765985 (o
en hexadecimal 0x00FFD421) es un numero que almacenamos en la posición
de memoria de "clase1".

O sea que datoA ocupa las posiciones de memoria 16765985, 16765986,
16765987y 16765988. 4 * 8 bits = 32 bits para un int.
Y datoB ocupa las posiciones de memoria 16765989, 16765991, 16765992 y
16765993.


Con:
MiClase clase2 = new MiClase();
Pasa lo mismo, se reserva un espacio físico de memoria para clase2 y
se graba el valor de la posición de memoria.

Jeje, no es sencillo a la primera. Lo vuelvo a repetir con otras
palabras, se vé la "luz" cuando se entiende.

¿Cual es la diferencia entre...
int numero = 3;
MiClase clase1 = new MiClase(); ?

NINGUNA EN TERMINOS NUMERICOS.
"numero" es una forma de acceder a una posición de memoria donde
grabar 3.
"clase1" es una forma de acceder a una posición de memoria donde
grabar 16765985.

Luego claro, "clase1" mola más porque podemos hacer:

clase1.datoB = 5;

Tan fácil, así en una sola línea, ¿qué pasa entonces? (repito que
estoy simplificando mucho mucho mucho)
- clase1 ocupa una posicion de memoria donde está almacenado el valor
16765985, OTRA posición de memoria donde hay "sitio" para dos enteros,
datoA en 16765985 y datoB en 16765985 + 4 = 16765989.
- por tanto escribimos 5 sobre los 4 bytes que están en la posición de
memoria 16765989.

Y seguimos tan félices, porque funciona como queremos.

{
MiClase obj1 = new MiClase();
MiClase obj2 = new MiClase();
}

Estamos seguros que obj1.datoA, obj1.datoB, obj2.datoA, obj2.datoB son
objetos independientes y no se "pisan" unos a otros.

Después de todo este rollo creo que se entiende mejor qué pasa cuando
hacemos:

obj2 = obj1;

Estamos grabando el número 16765985 en obj2. O sea que cuando hacemos:

obj2.datoB = 200; estamos modificando la misma posición de memoria que
ocupa obj1.datoA.



¿Qué pasa con las clases que tienen variables que almacenan otras
clases?
class MiClase
{
public int datoA = 3; // Esto es un ejemplo, no se hace,
"public" para variables es malo.
public int datoB = 5;
public DataSet ds = new DataSet();
}
...
{
MiClase obj = new MiClase();
}

¿Cuanto ocupa MiClase?, pues muy poco, dos int y un valor de una
posición de memoria, o sea que como tres int simplificando mucho.
¿Donde está el DataSet?, pues en otra posición de memoria
independiente a la de MiClase.

O sea, "obj" vale 783785837, posición de memoria para dos int y para
"ds" que vale 843287538, posición de memoria en donde estan las
variables que soportan el objeto DataSet.

¿Cómo "viajan" los objetos entre llamadas a funciones?

void Funcion(MiClase parametro)
{
parametro.datoA = 20;
}
...
{
MiClase obj = new MiClase();

Funcion(obj);

obj.datoA ¿cuanto vale?
}

Vale 20, ¿por qué?
Pues porque sí, jeje.
Como en el ejemplo del int, qué es lo que pasa:
"obj" vale 73464785. "parametro" ocupa una posición de memoria
diferente de "obj", pero en la llamada a la funcion se le copia el
valor 73464785.
Por tanto, parametro.datoA = 20 graba 20 en la misma posicion de
memoria de obj.datoA.

Algo muy diferente sería que Funcion hiciera:

void Funcion(MiClase parametro)
{
parametro = new MiClase();

parametro.datoA = 20;
}

En este caso, parametro vale una posición de memoria diferente a obj y
sus variables son independientes.

Y por fín, recordando el ejemplo con int, ¿como funciona ref con
objetos?

void Funcion(ref MiClase parametro)
{
parametro = new MiClase(); // "parametro" y "obj" ocupan la
misma posición de memoria.
// Por tanto "obj" ahora vale la posición de memoria recien reservada
para new MiClase.

parametro.datoA = 20;
}
...
{
MiClase obj = new MiClase();
MiClase obj2 = obj;

obj2.datoA = 50; // Modificamos obj a través de obj2 porque los
dos tienen la misma posición de memoria devuelta por new MiClase()

Funcion(ref obj);

obj2.datoA ¿cuanto vale?
}

obj2.datoA vale 50, ¿por qué?
"obj" y "obj2" son variables independientes cada una almacenando
diferentes valores de direcciones de memoria.

Al principio, las dos variables valían lo mismo, pero el valor de la
posición de memoria almacenado en "obj" ha sido modificado en Funcion.


Saludos, ¡vaya tocho!

Paco Ferre

On 26 oct, 13:41, Alfredo Novoa wrote:
El Sat, 25 Oct 2008 21:51:00 -0700, Hugo Nugra escribió:

>> Te estás haciendo un lío. ObjA contiene una referencia y no hay ninguna
>> referencia hacia ObjA. Las referencias no apuntan a otras referencias. A no
>> ser que te pongas a trabajar con punteros de bajo nivel.
> Precisamente me refiero a eso al decir "En concepto".  si bien nosotros no
> trabajamos a bajo nivel, pero C# sí lo hace por nosotros.

Pero C# nunca hace eso.

> No se si
> técnicamente no estoy utilizando el término apropiado al decir "referencia",
> pero quiero hacer alusión a que otros objetos "apuntan" a ObjA para utilizar
> sus propiedades y métodos.

La terminología de la POO no es técnicamente apropiada, en especial la
palabra "objeto" que es la confusión de varios conceptos diferentes. Por
eso es tan difícil hablar sobre estas cosas.

ObjA es una variable de tipo referencia y nadie apunta hacia ella. Y por
otra parte los métodos y propiedades (operadores) no son de los "objetos"
(variables o valores o punteros) sino de las clases, que a su vez no son
más que tipos de datos.

Cuando haces:

ObjA = ObjB;

Lo que haces es que la variable de tipo puntero de ObjA apunte a la
variable que está siendo apuntada por la variable de tipo puntero ObjB.

Saludos
Respuesta Responder a este mensaje
#17 Alfredo Novoa
28/10/2008 - 14:01 | Informe spam
Hola Paco,

El Tue, 28 Oct 2008 04:12:23 -0700 (PDT), Paco Ferre escribió:

Usando el concepto "objeto" como el espacio de memoria reservado para
una instancia de una clase la frase podría quedar un poco más clara.



En esa frase "instancia" está mal dicho, por que "instancia" significa
"petición", y no tiene sentido.

Debería de ser "ejemplar", y en ese caso: "espacio reservado para un
ejemplar de un tipo" es una definición de variable que todavía podría
mejorarse.

Yo creo que es mucho mejor usar el término "variable" que el término
"objeto". Por que "variable" siempre significa lo mismo, y cada uno le
llama objeto a lo que le da la gana y a menudo "objeto" cambia de
significado varias veces en un mismo párrafo y por supuesto sin avisar.
Cuando en un texto pone "objeto" hay que intentar deducir lo que significa
por el contexto y muchas veces ni siquiera se puede.

Por ejemplo objeto unas veces significa lo que tu dices, otras veces
significa el valor almacenado en ese espacio de memoria, otras veces
significa la variable de tipo puntero, otras veces dos cosas de estas a la
vez, otras veces las tres y otras veces puede significar bastantes otras
cosas :-)


Saludos
Respuesta Responder a este mensaje
#18 Paco Ferre
29/10/2008 - 08:26 | Informe spam
On 28 oct, 14:01, Alfredo Novoa wrote:
Hola Paco,

El Tue, 28 Oct 2008 04:12:23 -0700 (PDT), Paco Ferre escribió:

> Usando el concepto "objeto" como el espacio de memoria reservado para
> una instancia de una clase la frase podría quedar un poco más clara.

En esa frase "instancia" está mal dicho, por que "instancia" significa
"petición", y no tiene sentido.

Debería de ser "ejemplar", y en ese caso: "espacio reservado para un
ejemplar de un tipo" es una definición de variable que todavía podría
mejorarse.

Yo creo que es mucho mejor usar el término "variable" que el término
"objeto". Por que "variable" siempre significa lo mismo, y cada uno le
llama objeto a lo que le da la gana y a menudo "objeto" cambia de
significado varias veces en un mismo párrafo y por supuesto sin avisar.
Cuando en un texto pone "objeto" hay que intentar deducir lo que significa
por el contexto y muchas veces ni siquiera se puede.

Por ejemplo objeto unas veces significa lo que tu dices, otras veces
significa el valor almacenado en ese espacio de memoria, otras veces
significa la variable de tipo puntero, otras veces dos cosas de estas a la
vez, otras veces las tres y otras veces puede significar bastantes otras
cosas :-)

Saludos



Jeje, muy cierto :)

Saludos
email Siga el debate Respuesta Responder a este mensaje
Ads by Google
Help Hacer una pregunta AnteriorRespuesta Tengo una respuesta
Search Busqueda sugerida