none
Devolver nombre de objeto RRS feed

  • Pregunta

  • Hola comunidad

    Pongo un ejemplo del problema que me estoy encontrando

    Tengo una clase Base y otra que hereda de ella

        public class Base
        {
    
        }
    
        public class Clase : Base
        {
    
        }


    Un método que devuelve el nombre del objeto que se le pasa

            public string NombreObjeto(object clase)
            {
                return clase.GetType().Name;
            }


    ahora quiero que me devuelva los nombres de las clases de le paso


    var clase = new Clase(); var base1 = (Base)clase; var base2 = new Base(); Console.WriteLine(NombreObjeto(clase)); Console.WriteLine(NombreObjeto(base1)); Console.WriteLine(NombreObjeto(base2));


    Los valores que me devuelve son:

    Clase
    Clase <-
    Base

    En cambio en base1 lo convierto en Base porque me sigue devolviendo el nombre de Clase.

    Como puedo hacer para obtener:

    Clase
    Base <-
    Base

    Saludos

    martes, 12 de mayo de 2020 18:52

Respuestas

  • No, el "nameof" no se resuelve en tiempo de ejecución igual que el GetType. El nameof se resuelve en tiempo de compilación, por lo que nameof(Base) es exactamente lo mismo que "Base". Es solo "cola sintáctica" para el compilador, no afecta al tiempo de ejecución.

    Cambiarlo por un atributo no te vale, porque los atributos no participan en el polimorfismo; no puedes tener un atributo virtual que sea sobreescrito por la clase hija. Así que no vale para sustituir a la propiedad en este contexto. En cualquier caso, tendrías que leerlo por reflexión partiendo del GetType... pero para eso no necesitas un atributo, el propio GetType te daría el nombre de la clase. Y si quieres el nombre de la base, tendrías que usar reflexión para obtener el type de la base; ya puestos a hacer eso, el type te da el nombre de la clase, no necesitarías un paso más para leer el atributo.

    Y no, instanciando la clase 1000 veces no tendrías 1000 copias de la propiedad. Dado que la propiedad es una constante, se compila en el segmento de código y existe una sola copia para todas las instancias. Solo tendrías 1000 copias si utilizase un "backing store" (un campo de la clase) para guardar una copia de la constante. No sé si el compilador es lo bastante inteligente para no generar ese campo cuando la propiedad es de solo-lectura y su valor se inicializa con una constante. Siempre podrías quitar la propiedad automática y sustituirla por una propiedad explícita que devuelva la constante para garantizar que no usa backing store:

    public override string NombreClase { get {return nameof(Base); } }

     

    • Marcado como respuesta Juan FA miércoles, 13 de mayo de 2020 17:36
    miércoles, 13 de mayo de 2020 17:07
    Moderador
  • Seria una solución momentánea

    Al contrario, es una solución bastante buena. Que por cierto, funciona precisamente gracias al polimorfismo.

    Si quieres poder usarlo como en el ejemplo del principio, en el que hacías new Base, tendrás que cambiar "abstract" por "virtual" y darle una implementación. De lo contrario, te obliga a marcar la clase como abstract y no se puede instanciar.

    Una sugerencia de cara a la mantenibilidad futura: Si tienes una versión de C# lo suficientemente moderna, en lugar de poner "Clase" entre comillas en la propiedad, ponle nameof(Clase). Esto hace que se renombre automáticamente si alguna vez renombras la clase, mientras que si estuviese entre comillas tendrías que acordarte de renombrarlo a mano.

    • Marcado como respuesta Juan FA miércoles, 13 de mayo de 2020 17:36
    miércoles, 13 de mayo de 2020 14:44
    Moderador

Todas las respuestas

  • Hola Juan FA, 

      

    Gracias por levantar tu consulta en los foros de MSDN. Entendimos su pregunta y vamos a darle seguimiento para buscar la mejor repuesta pertinente al caso.  

    Cualquier duda referente a productos Microsoft, puedes consultarnos. Es un gusto informarte. 

    Gracias por usar los foros de MSDN.   

    Oystein Edwards 

     ____________________________ 

      

    Por favor recuerde "Marcar como respuesta" las respuestas que hayan resuelto su problema, es una forma común de reconocer a aquellos que han ayudado, y hace que sea más fácil para los otros visitantes encontrar la solución más tarde.  

    Microsoft ofrece este servicio de forma gratuita, con la finalidad de ayudar a los usuarios y la ampliación de la base de datos de conocimientos relacionados con los productos y tecnologías de Microsoft.   

    Este contenido es proporcionado "tal cual" y no implica ninguna responsabilidad de parte de Microsoft. 

    martes, 12 de mayo de 2020 19:16
    Moderador
  • Deleted
    miércoles, 13 de mayo de 2020 3:03
  • Me temo que esta pregunta indica que no has comprendido bien cómo funcionan las clases. Cuando haces esto:

    var base1 = (Base)clase;

    eso no convierte clase al tipo Base. La clase base puede contener a cualquiera de sus hijas. No las convierte a la madre, las guarda como hijas. Y esto es necesario porque es el fundamento en el que se basa el polimorfismo; si la madre no guardase la hija no tendríamos el polimorfismo de la orientación a objetos.

    Así que cuando llamas a NombreObjeto(base1), el objeto que recibe la subrutina NombreObjeto es realmente "Clase", no es "Base". Dentro de NombreObjeto no se recibe nada que le indique que antes hiciste un cast a Base, porque ese cast no hace nada. No se guarda esa conversión en ningún sitio.

    miércoles, 13 de mayo de 2020 5:22
    Moderador
  • Gracias CppMiguel por el interés, pero no sabría el orden de la declaración de las variables, seria muy complicado implantar ese código.

    Alberto tienes toda la razón, me falta mucha lectura, ya se algo nuevo :)

    Para salir del paso he pensado esto

    public class Base {

    public abstract string NombreClase {get;} } public class Clase : Base {

    public override string NombreClase {get;} = "Clase"; }

    Seria una solución momentánea,  pero seguramente me a llegado a esto por un mal planteamiento.

    Saludos

    miércoles, 13 de mayo de 2020 9:36
  • Seria una solución momentánea

    Al contrario, es una solución bastante buena. Que por cierto, funciona precisamente gracias al polimorfismo.

    Si quieres poder usarlo como en el ejemplo del principio, en el que hacías new Base, tendrás que cambiar "abstract" por "virtual" y darle una implementación. De lo contrario, te obliga a marcar la clase como abstract y no se puede instanciar.

    Una sugerencia de cara a la mantenibilidad futura: Si tienes una versión de C# lo suficientemente moderna, en lugar de poner "Clase" entre comillas en la propiedad, ponle nameof(Clase). Esto hace que se renombre automáticamente si alguna vez renombras la clase, mientras que si estuviese entre comillas tendrías que acordarte de renombrarlo a mano.

    • Marcado como respuesta Juan FA miércoles, 13 de mayo de 2020 17:36
    miércoles, 13 de mayo de 2020 14:44
    Moderador
  • Perdón Alberto, pero el código esta mal seria

    public class Clase : Base {

    public override string NombreClase {get;} = "Base"; }

    Busco que me devuelva el nombre de la clase base, y namesof(Clase) me devolvería la clase que lo podría obtener con el GetType().name

    Estoy buscando en añadirle un attributo, no se si se podrá, nunca he trabajado con ellos, algo a sin:


    [NombreClase("Base")]
    public class Clase : Base
    {
    }

    Aunque el sistema anterior me funciona, si la clase esta instanciado por ejemplo 10000 veces, tendría 10000 propiedades de NombreClase con el mismo valor innecesariamente, por eso ahora quiero mirar de añadir un attributo y de paso aprendo algo mas. 

    Alguna idea

    Edito: Me imagino que lo mismo que pasa con las propiedad NombreClase pasaría igual con un attributo, no?
    que seria mejor?

    Gracias
    Saludos




    • Editado Juan FA miércoles, 13 de mayo de 2020 16:40
    miércoles, 13 de mayo de 2020 16:02
  • No, el "nameof" no se resuelve en tiempo de ejecución igual que el GetType. El nameof se resuelve en tiempo de compilación, por lo que nameof(Base) es exactamente lo mismo que "Base". Es solo "cola sintáctica" para el compilador, no afecta al tiempo de ejecución.

    Cambiarlo por un atributo no te vale, porque los atributos no participan en el polimorfismo; no puedes tener un atributo virtual que sea sobreescrito por la clase hija. Así que no vale para sustituir a la propiedad en este contexto. En cualquier caso, tendrías que leerlo por reflexión partiendo del GetType... pero para eso no necesitas un atributo, el propio GetType te daría el nombre de la clase. Y si quieres el nombre de la base, tendrías que usar reflexión para obtener el type de la base; ya puestos a hacer eso, el type te da el nombre de la clase, no necesitarías un paso más para leer el atributo.

    Y no, instanciando la clase 1000 veces no tendrías 1000 copias de la propiedad. Dado que la propiedad es una constante, se compila en el segmento de código y existe una sola copia para todas las instancias. Solo tendrías 1000 copias si utilizase un "backing store" (un campo de la clase) para guardar una copia de la constante. No sé si el compilador es lo bastante inteligente para no generar ese campo cuando la propiedad es de solo-lectura y su valor se inicializa con una constante. Siempre podrías quitar la propiedad automática y sustituirla por una propiedad explícita que devuelva la constante para garantizar que no usa backing store:

    public override string NombreClase { get {return nameof(Base); } }

     

    • Marcado como respuesta Juan FA miércoles, 13 de mayo de 2020 17:36
    miércoles, 13 de mayo de 2020 17:07
    Moderador
  • Hola de nuevo

    Tienes razón, me estaba complicando, cuando algo se te mete en la cabeza, cuesta salir jajaja

        
        public abstract class BaseClase
        {
            public abstract string NombreClase { get; }
        }
    
        public class Clase : BaseClase
        {
            public override string NombreClase => nameof(Clase);
        }
    
        public class ClaseView : Clase
        {
            public override string NombreClase => nameof(Clase);
        }

    Gracias



    • Editado Juan FA miércoles, 13 de mayo de 2020 21:59
    miércoles, 13 de mayo de 2020 17:36