2010-06-14 9 views
8

Creo que está bien en programación algorítmica, si ese es el término correcto? Solía ​​jugar con el turbo pascal y el lenguaje ensamblador 8086 en la década de 1980 como un hobby. Pero solo proyectos muy pequeños y realmente no he hecho ninguna programación en los últimos 20 años desde entonces. Así que estoy luchando por entenderme como un nadador que se está ahogando.¿Qué sucede cuando creas una instancia de un objeto que no contiene ningún estado en C#?

Así que tal vez esta es una pregunta muy niave o sólo estoy haciendo no tiene sentido en absoluto, pero decir que tengo un objeto clase de la siguiente manera:

class Something : IDoer 
{ 
    void Do(ISomethingElse x) 
    { 
     x.DoWhatEverYouWant(42); 
    } 
} 

Y entonces hago

var Thing1 = new Something(); 
var Thing2 = new Something(); 

Thing1.Do(blah); 
Thing2.Do(blah); 

hace Thing1 = Thing2? ¿"algo nuevo()" crea algo? ¿O no es muy diferente de tener una clase estática, excepto que puedo pasarla e intercambiarla, etc.

Es el procedimiento "Hacer" en la misma ubicación en la memoria para Thing1 (blah) y Thing2 (bla) objetos? Quiero decir cuando lo ejecutas, ¿significa que hay dos procedimientos Something.Do o solo uno?

Respuesta

7

Definitivamente, hay dos objetos diferentes en la memoria. Cada objeto consumirá 8 bytes en el montón (al menos en sistemas de 32 bits); 4 para el syncblock y 4 para el manejador de tipo (que incluye la tabla de métodos). Aparte de los datos de estado definidos por el sistema, no hay otros datos de estado definidos por el usuario en su caso.

Hay una sola instancia del código para el método Something.Do. El puntero de manejador de tipo que tiene cada objeto es cómo CLR localiza los diferentes métodos para la clase. Entonces, aunque hay dos objetos diferentes en la memoria, ambos ejecutan el mismo código. Como se declaró Something.Do como un método de instancia, tendrá un puntero this pasado internamente para que el código pueda modificar los miembros correctos de la instancia según el objeto que invoca el método. En su caso, la clase Something no tiene miembros de instancia (y, por lo tanto, no tiene un estado definido por el usuario), por lo que esto es bastante irrelevante, pero aún así sucede.

5

No, no son lo mismo. Son dos instancias separadas de la clase Something. Resulta que están idénticamente instanciados, eso es todo.

+0

Pero, ¿qué es esto en realidad en la memoria? Detrás de la referencia, hay un puntero que apunta al estado del objeto en la memoria. Entonces, ¿a dónde apunta? –

+0

Es fantástico que desee este nivel de detalle, pero es difícil responder con tantos detalles aquí. Sin embargo, puedo recomendar un excelente libro que responderá a sus preguntas desde un punto de vista .NET, que es el CLR de Jeffrey Richter a través de C#. –

+0

Creo que Brian Gideon respondió esto. –

0

Thing1! = Thing2
Estos son dos objetos diferentes en la memoria.

El código de método Do está en el mismo lugar para ambos objetos. No es necesario almacenar dos copias diferentes del método.

4

Crearía 2 objetos "vacíos", habría una pequeña asignación en el montón para cada objeto.

Pero el método "Do" siempre está en el mismo lugar, no tiene nada que ver con la ausencia de estado. El código no se almacena 'en' una clase/objeto. Solo hay 1 pieza de código correspondiente a Do() y tiene un parámetro 'oculto' this que apunta a la instancia de Algo a lo que se llamó.

12

Son dos objetos separados; simplemente no tienen estado.

consideran este código:

var obj1 = new object(); 
var obj2 = new object(); 

Console.WriteLine(object.ReferenceEquals(obj1, obj2)); 

Se dará salida False.

El hecho de que un objeto no tenga estado no significa que no se asigne como cualquier otro objeto. Simplemente ocupa muy poco espacio (como un object).

En respuesta a la última parte de su pregunta: solo hay un método Do. Los métodos no se almacenan por instancia sino por clase. Si lo piensas, sería extremadamente inútil almacenarlos por instancia. Cada método de llamada a Do en un objeto Something es realmente el mismo conjunto de instrucciones; todo lo que difiere entre las llamadas de diferentes objetos es el estado del objeto subyacente (si la clase Something tenía algún estado para empezar, eso es).

Lo que esto significa es que los métodos de instancia en los objetos de la clase son realmente los mismos que los métodos estáticos.

Puede pensar que todos los métodos de nivel de instancia se tradujeron en secreto de la siguiente manera (no estoy diciendo que esto sea estrictamente cierto, solo que podría pensarlo de esta manera y tiene sentido):

// appears to be instance-specific, so you might think 
// it would be stored for every instance 
public void Do() { 
    Do(this); 
} 

// is clearly static, so it is much clearer it only needs 
// to be stored in one place 
private static Do(Something instance) { 
    // do whatever Do does 
} 

nota interesante: lo anterior hipotética "traducción" explica más o menos exactamente cómo los métodos de extensión funcionan: son métodos estáticos, sino por calificar su primer parámetro con la palabra clave this, de repente ven como métodos de instancia .

+0

me gustaría ver una respuesta erótica a eso. Sospecho que debido a que la clase no está sellada y hereda de una interfaz que habrá algo de memoria para algún tipo de puntero de método virtual ... el punto es que su última pregunta es realmente interesante, pero requiere conocimiento aterrador. –

+0

Por favor, vea mi comentario a David M –

+0

... y es una pregunta separada de la pregunta aquí. –

0

Cada tipo de referencia (Thing1, Thing2) apunta a una dirección física diferente en la memoria principal, ya que se han instanciado por separado. Lo que se señala en la memoria son los bytes utilizados por el objeto, ya sea que tenga un estado o no (siempre tiene un estado, pero si tiene un estado declarado/inicializado).

Si asignó un tipo de referencia a otro tipo de referencia (Thing2 = Thing1;) entonces sería la misma porción de memoria utilizada por dos tipos de referencia diferentes, y no se realizaría ninguna nueva instanciación.

1

Conceptualmente, Thing1 y Thing2 son objetos diferentes, pero solo hay un procedimiento Something.Do.

El tiempo de ejecución .Net asigna un poco de memoria a cada uno de los objetos que crea, un trozo de Thing1 y otro de Thing2. El propósito de este trozo de memoria es almacenar (1) el estado del objeto y (2) una dirección de cualquier procedimiento que pertenezca al objeto. Sé que no tiene ningún estado, pero al tiempo de ejecución no le importa, todavía conserva dos referencias separadas a dos trozos de memoria separados.

Ahora, su método "Do" es el mismo para Thing1 y Thing2, el tiempo de ejecución solo conserva una versión del procedimiento en la memoria.

La memoria asignada Thing1 incluye la dirección del método Do. Cuando invoque el método Do en Thing1, buscará la dirección de su método Do para Thing1 y ejecutará el método. Lo mismo sucede con el otro objeto, Thing2. Aunque los objetos son diferentes, se llama al mismo método Do para Thing1 y Thing2.

Lo que se reduce a esto es que Thing1 y Thing2 son diferentes, ya que los nombres "Thing1" y "Thing2" se refieren a diferentes áreas de la memoria. El contenido de esta memoria es el mismo en ambos casos, una sola dirección que apunta al método "Do".

Bueno, esa es la teoría, de todos modos.Debajo del capó, puede haber algún tipo de optimización (vea http://www.wrox.com/WileyCDA/Section/CLR-Method-Call-Internals.id-291453.html si está interesado), pero para la mayoría de los propósitos prácticos, lo que dije es la forma en que funcionan las cosas.

0

Una buena forma de pensar en el nuevo constructor(), es que realmente está llamando al método dentro de su clase, cuya única responsabilidad es producirle una nueva instancia de un objeto cortado de su clase.

lo que ahora puede tener varias instancias de la misma clase que funcionan alrededor en el manejo de todo tipo de situaciones en tiempo de ejecución: D

por lo que el CLR, que está recibiendo de hecho 2 instancias separadas en memoria que contienen cada uno punteros a es muy similar a cualquier otro lenguaje OOP pero no tenemos que interactuar con los punteros, se traducen igual que los tipos sin referencia, ¡así que no tenemos que preocuparnos por ellos!

(hay punteros en C# si desea sacar de repente su palabra clave [inseguro]!)

Cuestiones relacionadas