0% encontró este documento útil (0 votos)
10 vistas9 páginas

Guia 1 - Programación II

Las ventanas modales y MDI se comparan, describiendo sus funciones, ventajas y desventajas. Los eventos al lograr/perder foco, cargar, visualizar o cerrar cada tipo de ventana también se describen. Se mencionan tres tipos de recursividad y la eficiencia de funciones recursivas. La pila de programa y desbordamiento se explican con un ejemplo recursivo.

Cargado por

Juli Rutar
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
10 vistas9 páginas

Guia 1 - Programación II

Las ventanas modales y MDI se comparan, describiendo sus funciones, ventajas y desventajas. Los eventos al lograr/perder foco, cargar, visualizar o cerrar cada tipo de ventana también se describen. Se mencionan tres tipos de recursividad y la eficiencia de funciones recursivas. La pila de programa y desbordamiento se explican con un ejemplo recursivo.

Cargado por

Juli Rutar
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 9

1) Compare utilización de Ventanas Modales en C#. con el uso de ventanas MDI.

Elabore un
cuadro comparativo de las funciones, ventajas y desventajas de cada una. ¿Qué eventos
puede analizar al lograr el foco, perder el foco, cargar, visualizar o cerrar una ventana de
cada tipo?

Presentan al usuario una ventana con un conjunto de controles y, según las acciones que el
usuario realiza sobre las mismas se producen eventos, a los cuales la aplicación reacciona
ejecutando algún algoritmo.

Ventanas Modales Ventanas MDI


Funciones Recopilar información Administración de documentos
múltiples
Confirmación y advertencias Agrupación de documentos
Seleccionar opciones Interacción entre documentos
Instrucciones o tutoriales Minimizar y maximizar
ventanas
Interactuar con elementos Navegación y administración
secundarios de ventanas
Presentar contenido
multimedia
Bloquear acciones del
formulario principal
Ventajas Capturan la atención del Optimización de espacio
usuario de manera efectiva
Recopilan información precisa Gestión eficiente de
de manera organizada documentos
Brindan instrucciones y ayuda Acceso rápido a documentos
en momentos clave
Hacen énfasis en la tarea Eficiencia de recursos
actual
Claridad en la interacción Mejora la experiencia del
usuario
Desventajas Interrupción del flujo de Complejidad Visual
trabajo
Dificultad para la multitarea Falta de foco
Complejidad de diseño
Dificultad de navegación

Evento Ventana Modal Ventana MDI


Lograr el foco GotFocus Activated
Perder el foco LostFocus Desactivated
Cargar Load Load
Visualizar Shown Shown
Cerrar FormClosed FormClosed
2) En el capítulo 8 de [3] y en los capítulos 6 y 7 de [2] se hace referencia a la utilización de
recursividad y al funcionamiento del STACK. ¿Cuáles son los tipos de recursividad
descriptos? ¿Cuál es la eficiencia de las funciones recursivas?

Los tipos de recursividad descriptos por Chaves, en “Aprenda a diseñar algoritmos” [3] son:
• Recursividad simple: se presenta cuando una función incluye un llamado a sí misma
con un argumento diferente. Ejemplo de este tipo de recursividad es la función
factorial (). Este tipo de recursividad se caracteriza porque puede pasarse fácilmente
a una solución iterativa.
• Recursividad múltiple: el cuerpo de una función incluye más de una llamado a la
misma función, por ejemplo, la función para calcular un valor de la serie Fibonacci.
• Recursividad anidada: se dice que una función recursiva es anidada cuando entre los
parámetros que se pasan a la función se incluye una invocación a la misma. Un
ejemplo de recursividad anidada es la solución al problema de Ackerman§
• Recursividad cruzada o indirecta: en este tipo de recursividad, el cuerpo de la
función no contiene un llamado a sí misma, sino a otra función; pero, la segunda
incluye un llamado a la primera. Puede ser que participen más de dos funciones.
Este tipo de implementaciones también se conoce como cadenas recursivas. Como
ejemplo de este tipo de recursividad se tiene la función para validar una expresión
matemática.

Las funciones recursivas, en muchas aplicaciones avanzadas, es más simple de visualizar y el


único medio práctico de implementar una solución.

3) Describa la pila de programa del sistema operativo, la forma en que se activan distintos
puntos de ejecución. Implemente un ejemplo de función recursiva y plantee un
seguimiento de la pila de llamadas de este. ¿Que implica el problema de desbordamiento
de la pila de programa o stackoverflow? De qué manera el IDE de Visual Studio le permite
conocer la pila de llamadas durante la ejecución y debug de una aplicación.

La pila es una estructura de datos donde se almacenan las llamadas a métodos en una
aplicación. Funciona siguiendo el principio "último en entrar, primero en salir" (LIFO), similar
a una pila de platos. Cuando un método se llama, su dirección de retorno se agrega a la pila,
y cuando retorna, se saca.

La pila también guarda la memoria para las variables locales de los métodos, conocido como
registro de activación o marco de pila. Cuando un método se llama, su registro de activación
se agrega a la pila; cuando retorna, se retira y las variables locales se eliminan. Si una
variable local es la única referencia a un objeto, cuando su registro se retira, el objeto será
eliminado por la "recolección de basura".

La memoria de la pila es limitada, y si hay más llamadas de métodos de las que pueden
almacenarse en la pila, ocurre un desbordamiento de pila, un error. Este problema surge
cuando la pila se llena de registros de activación y no puede manejar más llamadas.
Ejemplo de función recursiva

public static int Factorial(in


t n)
{
if (n == 0)
return 1;
else
return n * Factorial (n - 1);
}

• Se llama a Factorial (3).


• Se llama a Factorial (2) desde Factorial (3).
• Se llama a Factorial (1) desde Factorial (2).
• Se llama a Factorial (0) desde Factorial (1).
• Factorial (0) retorna 1.
• Factorial (1) retorna 1 * 1 = 1.
• Factorial (2) retorna 2 * 1 = 2.
• Factorial (3) retorna 3 * 2 = 6.

Como conocer la pila desde el IDE de VSC


Una flecha amarilla identifica el marco de la pila donde se encuentra actualmente el puntero
de ejecución. De forma predeterminada, la información de este marco de pila aparece en las
ventanas de origen, Locales, Autos, Inspección y Desensamblado. Para cambiar el contexto
del depurador a otro marco de la pila, cambie a otro marco de la pila.

4) ¿En qué casos se puede utilizar la repetitividad de los valores aleatorios generados por la
clase Random? Como es posible generarlos, como se puede evitar la generación de las
mismas secuencias. ¿Son valores realmente aleatorios?

La clase Random nos permite generar valores pseudoaleatorios variando los tipos de datos,
según el método que utilicemos. La repetitividad de los valores aleatorios generados, nos
pueden ser de utilidad a la hora de realizar pruebas y tests sobre cierto fragmento de código
o programa. Esto se debe a que para evaluar distintos algoritmos o funciones y así poder
analizar el tiempo de ejecución, cantidad de recursos empleados, entre otros, debemos
siempre correr un mismo set de elementos para mantener la consistencia de los test en
todas sus pruebas y casos.

Para generar la misma serie de valores aleatorios, debemos instanciar la clase Random
acompañada de una semilla en su constructor, esta ha de ser de tipo Int32. En caso de no
querer trabajar con las mismas secuencias de valores, debemos utilizar una sola instancia del
objeto Random. Los valores generados no son aleatorios en su sentido mas puro, sino que
son números generados a partir de un algoritmo, es por esto que pasándole la misma
semilla podemos deducir que la secuencia de valores obtenidos se repetiría.

5) Describa la combinación de modificadores Static y Readonly, en clases y constructores.


¿Cómo se deben utilizar para contar objetos creados y destruidos? ¿Cómo asignar un
numero de secuencia a un objeto con estos recursos
La combinación de modificadores Static y Readonly a nivel de clases permite declarar
atributos que funcionen como variables constantes, con la diferencia de que al emplear esta
combinación se puede asignar un valor en tiempo de ejecución. Esto nos posibilita asignarle,
en el momento de instanciarla, el valor de otra variable previamente instanciada.

Para contar objetos creados y destruidos, utilizamos el modificador Static. Ya que, como crea
una variable de clase, esta no se instancia cada vez que se crea un objeto, y nos permite
mantener el valor. Lo que podemos hacer para tener un contador de objetos es incrementar
la variable estática desde el constructor del nuevo objeto.

Para contar los destruidos, decrementamos la variable en el lugar donde destruyamos el


objeto. Recordemos que la variable static no está ligada al ciclo de vida de cada objeto, sino
que está ligada a la clase que los contiene.
Para otorgar un número de secuencia a cada objeto, podemos emplear una variable de tipo
ReadOnly junto con otra variable de tipo static que incremente con cada instancia de un
objeto. Lo que nos va a permitir asignar el valor de esta variable a la variable ReadOnly,
garantizando que cada objeto contenga un valor diferente.

6) Investigue la clase TimeSpan y sus usos para calcular tiempos de ejecución combinado con
DateTime.Now y StopWatch.

La clase TimeSpan nos permite calcular el intervalo de diferencia entre dos fechas o periodos
de tiempo. Este objeto a su vez cuenta con propiedades que nos permite acceder a sus
distintos atributos.

• Days: Obtiene el componente de días del intervalo de tiempo representado por la


estructura TimeSpan actual.
• Hours: Obtiene el componente de días del intervalo de tiempo representado por la
estructura TimeSpan actual.
• Milliseconds: Obtiene el componente de milisegundos del intervalo de tiempo
representado por la estructura TimeSpan actual.
• Minutes: Obtiene el componente de minutos del intervalo de tiempo representado
por la estructura TimeSpan actual.
• Seconds: Obtiene el componente de segundos del intervalo de tiempo representado
por la estructura TimeSpan actual.
• Ticks: Obtiene el número de pasos que representa el valor de la estructura TimeSpan
actual.
• TotalDays: Obtiene el valor de la estructura TimeSpan actual, expresado en días
completos y fracciones de días.
• TotalHours: Obtiene el valor de la estructura TimeSpan actual, expresado en horas
completas y fracciones de horas.
• TotalMilliseconds: Obtiene el valor de la estructura TimeSpan actual, expresado en
milisegundos completos y fracciones de milisegundos.
• TotalMinutes: Obtiene el valor de la estructura TimeSpan actual, expresado en
minutos completos y fracciones de minutos.
• TotalSeconds: Obtiene el valor de la estructura TimeSpan actual, expresado en
segundos completos y fracciones de segundos.

Resulta importante saber que esta estructura representa un intervalo general sin referencia
a un punto inicial o final determinado, es decir, no es posible expresarlo en términos de años
y meses. Por esto utiliza días, para así mantener la coherencia, ya que el número de días en
unidades de tiempo mayores no varía, a diferencia de como en meses y años que si lo hace.

7) Investigue la Clase ArrayList. Identifique y detalle sus principales propiedades y métodos.

Métodos/Propiedades:

• Add: Agrega un objeto object al objeto ArrayList y devuelve un int que especifica el
índice en el que se agregó el objeto object.
• Capacity: Propiedad que obtiene y establece el número de elementos para los que
se reserva espacio en un momento dado, dentro del objeto ArrayList.
• Clear Elimina todos los elementos del objeto ArrayList.
• Contains: Devuelve true si el objeto object especificado está en el objeto ArrayList;
en caso contrario, devuelve false.
• Count: Propiedad de sólo lectura que obtiene el número de elementos almacenados
en el objeto ArrayList.
• IndexOf: Devuelve el índice de la primera ocurrencia del objeto object especificado
en el objeto ArrayList.
• Insert: Inserta un objeto object en el índice especificado. Remove Elimina la primera
ocurrencia del objeto object especificado.
• RemoveAt: Elimina un objeto en el índice especificado.
• RemoveRange: Elimina un número especificado de elementos, empezando en un
índice especificado en el objeto ArrayList.
• Sort: Ordena el objeto ArrayList.
• TrimToSize: Establece la capacidad del objeto ArrayList al número de elementos que
contiene el objeto ArrayList en un momento dado (Count).
• CreateInstance: para crear un nuevo arreglo de un tipo especificado.
• LastIndexOf: para localizar la última ocurrencia de un objeto en un arreglo, o en una
porción de este.
• Reverse: para invertir el contenido de un arreglo, o de una porción de este.

8) ¿Qué ocurre en un objeto ArrayList cuando se intenta establecer la propiedad Capacity a


un valor menor que el tamaño actual del vector, y con la propiedad Count?

Dado un objeto de tipo ArrayList, con tres valores cargados, a la hora de llamar al método
Count, este nos arrojará “3”, y el método Capacity nos devolverá “4”. Si intentamos
establecer la capacidad del objeto a un valor menor que la cantidad de valores que este
contiene el programa nos lanzara un error, con la siguiente excepción:

System.ArgumentOutOfRangeException: capacidad menor que el tamaño actual.

Esto se debe a que no es posible establecer una capacidad menor a la cantidad de valores
que ya posee este objeto, debido a que esto nos generaría una pérdida de información.

La propiedad Count directamente no nos permite modificarla ya que la misma es de tipo


readonly.

9) ¿Como es posible identificar en un ArrayList si un objeto pertenece o no a una clase?


Para poder identificar si un objeto que se encuentra en un ArrayList es de un tipo de clase,
utilizamos el operador “is”. El operador “is” comprueba si el resultado de una expresión es
compatible con un tipo determinado.

Veamos un ejemplo

public bool Permiso(object obj)


{
bool resultado = false;
if (obj is Administrador)
bool = true;
return bool;
}

10) ¿Como se identifican las relaciones de composición y agregación? ¿Cuándo se identifica


una relación “tiene un”?

Dadas dos clases, A y B, se establece una relación cuando la clase A, llamada "Todo", tiene
una o más partes de la clase B (La cantidad de partes se determina mediante la
cardinalidad). Dado que la relación se define entre clases, pero ocurre entre objetos,
depende del ciclo de vida de estos.

La expresión "tiene un" a menudo sugiere una relación de composición o agregación. Si un


objeto A "tiene un" objeto B como parte de su descripción esencial, podría indicar una
relación de composición. Si un objeto A "tiene un" objeto B, pero el objeto B puede existir de
manera independiente o pertenecer a múltiples objetos A, esto podría sugerir una relación
de agregación.

En la composición, los objetos se crean conjuntamente. La clase "Todo", o la compuesta, es


responsable de la creación y destrucción de las partes (componentes). Los ciclos de vida
están fuertemente interconectados. Si el objeto compuesto se destruye, sus partes también
se destruyen. En la relación de composición, las partes no pueden pertenecer a más de un
objeto al mismo tiempo.

En una relación de Agregación, los ciclos de vida no están fuertemente interconectados; las
partes y el todo se crean y destruyen de manera independiente. Un objeto puede contener
otros objetos, pero las partes pueden existir independientemente del objeto compuesto. La
relación entre el objeto compuesto y sus partes es más débil que en la composición. Las
partes pueden pertenecer a múltiples objetos al mismo tiempo y no se destruyen
necesariamente cuando el objeto compuesto se destruye.

11) ¿Qué se entiende por ciclo de vida de los objetos? ¿Como el ciclo de vida de los objetos
determina la diferenciación de las relaciones entre clases de agregación y composición?

El ciclo de vida de los objetos se refiere a las diferentes etapas por las que pasa un objeto
desde su creación hasta su eliminación. Desde su creación, donde se inicializan sus atributos
y se asigna un espacio de memoria para esos objetos. Pasando por el uso que se les da,
donde cambia el estado de estos a medida que se realicen las operaciones, en función de las
acciones realizadas sobre él. Cuando el objeto ha cumplido su propósito y ya no es necesario
para el programa puede ser liberado de la memoria o se pueden realizar tareas de limpieza y
liberación de recursos. Se procederá luego a la etapa de eliminación, cuando se requiera,
para liberar los recursos que el objeto haya estado utilizando.

El ciclo de vida de los objetos determina la diferenciación entre clases de agregación y


composición. En una relación de agregación el ciclo de vida de los objetos se refleja en que
los objetos de la clase “parte” pueden existir independientemente de la existencia de la clase
“todo”. Esto significa que los objetos “parte” pueden ser creados y eliminados por sí mismos,
y su vida útil no está estrictamente ligada a la vida útil de los objetos de la clase “todo”. La
clase contenedora mantiene una referencia a los objetos contenidos, pero no es responsable
de su creación y/o eliminación.

En cambio, si hablamos de composición, tenemos una clase “todo” que contiene objetos de
otra clase “parte” de manera que los objetos componentes son esenciales para la existencia
de la clase compuesta (todo). En este caso la vida útil de los objetos componentes está
completamente controlada por la clase compuesta. Cuando esta se crea o se destruye, los
objetos “parte” también son creados o destruidos en consecuencia. Los ciclos de vida en
este caso están fuertemente ligados entre sí.

12) ¿Qué tipo de jerarquía define la relación “es un” entre objetos de diferentes clases? ¿Qué
características tiene la invocación de constructores en dichas relaciones? ¿Cuál es el
primero en ejecutarse? ¿Cuál es el primero en terminar su ejecución?

La jerarquía que define la relación “es un” en el modelado entre objetos de diferentes clases
es de Generalización. En Programación Orientada a Objetos, esta relación se llama Herencia.

Al crear una instancia de un objeto de clase derivada se empieza una cadena de llamadas a
los constructores, en los que el constructor de la clase derivada, antes de realizar sus propias
tareas, invoca al constructor de su clase base directa, ya sea en forma explícita (por medio
de un inicializador de constructor con la referencia base) o implícita (llamando al constructor
predeterminado o sin parámetros de la clase base). Si la clase base se deriva de otra clase
(como sucede con cualquier clase, excepto object), el constructor de la clase base invoca al
constructor de la siguiente clase que se encuentre a un nivel más arriba en la jerarquía, y así
en lo sucesivo.

El último constructor que se llama en la cadena es siempre el de la clase object. El cuerpo del
constructor original de la clase derivada termina de ejecutarse al último.

13) ¿Qué tipo de asignación de objetos se pueden realizar en variables declaradas en dos
diferentes clases relacionadas por herencia? ¿Una variable declarada del tipo de la clase
base admite un objeto de la clase derivada? ¿Y viceversa? ¿Por qué?

Una variable declarada de tipo base admite un objeto de la clase derivada, debido a que la
clase derivada cuenta con todos los miembros de la clase base, más los suyos, pero debemos
tener en cuenta que, si intentásemos utilizar un método propio de la clase derivada, en un
objeto declarado de la clase base, obtendríamos un error. Esta manera de declarar objetos
de clase base y asignarle un objeto de clase derivada se conoce como “upcasting”.

Cuando asignamos un objeto de clase base a una variable de clase derivada, lo reconocemos
como “downcasting”. En el es necesario que realicemos un casteo. Debemos tener en cuenta
que, si el objeto originalmente no es una instancia de la clase derivada, esto generará la
siguiente excepción:
System.InvalidCastException: 'No se puede convertir un objeto de tipo
'ConsoleApp1.ClaseBase' al tipo 'ConsoleApp1.ClaseDerivada'.'

14) ¿Qué característica brinda la sobreescritura de métodos? ¿Por qué objetos de la misma
jerarquía necesitan comportamiento diferente? ¿Qué relaciones tienen los modificadores
virtual y override?

La sobreescritura de métodos es una característica muy útil en programación orientada a


objetos. A través de ella podemos hacer que dos elementos, los cuales comparten jerarquía,
actúen de forma distinta utilizando el mismo método, pero con distinta implementación.

Muchas veces los objetos de misma jerarquía requieren comportamiento diferente por que
actúan de forma diferente, por ende, la implementación no es la misma en todos. Tomemos
como ejemplo una clase Vehículo, de ella heredaran las clases Automóvil y Moto. Sabemos
que la clase vehículo debería contar con un método “Acelerar()”, sin embargo, la manera de
acelerar en Automóvil y en Moto difiere, esta es la razón por la cual debemos sobrescribir
estos métodos implementando en cada uno de ellos la forma que le corresponda.

Utilizamos el modificador “virtual” en métodos y propiedades para así “habilitar” la


sobreescritura de la implementación especifica de aquellos métodos y propiedades en clases
descendientes. El modificador “override”, el cual utilizamos en las clases derivadas, nos
indica que la implementación que se hará sobre ese método o propiedad sobrescribirá la ya
existente implementación de la clase base.

15) ¿Qué representatividad tiene una clase abstracta? ¿Porque se definen? ¿Qué finalidad
tienen?

La representatividad de una clase abstracta radica en proporcionar una estructura común y


un conjunto de características que serán compartidas por sus clases derivadas.

Las clases abstractas se definen para establecer una especie de contrato o plantilla que
define métodos (funciones) y propiedades que deben ser implementados por las clases hijas
que heredan de la clase abstracta.

La finalidad principal de las clases abstractas es la de abstraer y encapsular comportamientos


y propiedades comunes que se esperan en las clases derivadas. Esto promueve la
reutilización de código y la consistencia en la estructura de las clases en un programa
orientado a objetos.

16) ¿Qué caracteriza la creación de métodos abstractos? ¿Qué reglas se aplican para su
declaración e implementación? ¿Qué consecuencias tienen?

Los métodos abstractos son aquellos que se declaran en una clase abstracta pero no se les
proporciona una implementación concreta en dicha clase. En cambio, las clases derivadas
que heredan de la clase abstracta están obligadas a implementar estos métodos según sus
necesidades y contexto específico.

Las clases derivadas concretas deben proporcionar implementaciones para cada descriptor
de acceso declarado en la propiedad abstracta.
Los constructores y los métodos static no pueden declararse abstract. Los constructores no
se heredan, por lo que un constructor abstract nunca podría implementarse. De manera
similar, las clases derivadas no pueden redefinir métodos static, por lo que un método
abstract static nunca podría implementarse.

17) ¿Qué efecto tienen el modificador de acceso protected? ¿Dónde se aplica? ¿Por qué?

El uso del acceso protected ofrece un nivel intermedio de acceso entre public y private. Se
puede acceder a los miembros protected de una clase base a través de los miembros de esa
clase base y de los miembros de sus clases derivadas.

Este modificador de acceso se aplica en la clase base donde aparece por primera vez el
método o atributo. Esto es porque todos los miembros no private de la clase base retienen
su modificador de acceso original cuando se convierten en miembros de la clase derivada,
por lo que solo es necesario indicarlo la primera vez.

18) ¿Qué efecto tiene el modificador de acceso sealed? ¿Dónde?

Un método que se declara como sealed en una clase base no puede redefinirse en una clase
derivada.

Una clase que se declara como sealed no puede ser una clase base (es decir, una clase no
puede extender a una clase sealed). Todos los métodos en una clase sealed son sealed de
manera implícita.

La declaración de un método sealed no puede cambiar nunca, por lo que todas las clases
derivadas utilizan la misma implementación del método, y las llamadas a los métodos sealed
se resuelven en tiempo de compilación; a esto se le conoce como vinculación estática.

También podría gustarte