Es bien sabido por aquellos familiarizados con la historia que C # y .NET Framework comenzaron como esencialmente "Delphi reescrito para sentirse como Java", diseñado por el desarrollador principal detrás de Delphi, Anders Hejlsberg. Las cosas han divergido bastante desde entonces, pero al principio las similitudes eran tan obvias que incluso hubo algunas especulaciones serias de que .NET en realidad era originalmente el producto de Borland.
Pero he estado mirando algunas cosas de .NET últimamente, y una de las características más interesantes y útiles de Delphi parece faltar por completo: el concepto de clases como un tipo de datos de primera clase. Para aquellos que no están familiarizados con él, el tipo TClass
representa una referencia a una clase, similar al Type
tipo en .NET. Pero donde .NET usa Type
para la reflexión, Delphi lo usa TClass
como una parte incorporada muy importante del lenguaje. Permite varios modismos útiles que simplemente no existen y no pueden existir sin él, como las variables de subtipo de clase y los métodos de clase virtual.
Cada lenguaje OO tiene métodos virtuales, en los que diferentes clases implementan el mismo concepto fundamental de un método de diferentes maneras, y luego se llama al método correcto en tiempo de ejecución en función del tipo real de la instancia del objeto al que se llama. Delphi extiende este concepto a las clases: si tiene una referencia TClass definida como un subtipo de clase específico (es class of TMyClass
decir, la variable puede aceptar cualquier referencia de clase que herede TMyClass
, pero no cualquier cosa fuera de la jerarquía) que tenga métodos virtuales de ámbito de clase unidos a se pueden llamar sin una instancia utilizando el tipo real de la clase. La aplicación de este patrón a los constructores hace que la implementación de Factory sea trivial, por ejemplo.
No parece haber nada equivalente en .NET. Con lo útil que son las referencias de clase (y especialmente los constructores virtuales y otros métodos de clase virtual), ¿alguien ha dicho algo sobre por qué se quedaron fuera?
Ejemplos específicos
Deserialización de formularios
El Delphi VCL guarda formularios en DFM
formato, un DSL para describir una jerarquía de componentes. Cuando el lector de formularios analiza los datos de DFM, se ejecuta en objetos que se describen así:
object Name: ClassName
property = value
property = value
...
object SubObjectName: ClassName
...
end
end
Lo interesante aquí es la ClassName
parte. Cada clase de componente registra su tiempo TClass
con el sistema de transmisión de componentes initialization
(piense que los constructores estáticos, solo un poco diferentes, se garantiza que sucederán inmediatamente al inicio). Esto registra cada clase en una cadena-> TClass hashmap con el nombre de la clase como clave.
Cada componente desciende de TComponent
que tiene un constructor virtual que toma un solo argumento, Owner: TComponent
. Cualquier componente puede anular este constructor para proporcionar su propia inicialización. Cuando el lector DFM lee el nombre de una clase, busca el nombre en el hashmap mencionado anteriormente y recupera la referencia de clase correspondiente (o genera una excepción si no está allí), luego llama al constructor virtual de TComponent, que se sabe que es bueno porque la función de registro toma una referencia de clase que se requiere para descender de TComponent, y usted termina con un objeto del tipo apropiado.
Al carecer de esto, el equivalente de WinForms es ... bueno ... un gran desastre para decirlo sin rodeos, ya que requiere que cualquier nuevo lenguaje .NET vuelva a implementar completamente su propia (des) serialización. Esto es un poco impactante cuando lo piensas; Dado que el objetivo de tener un CLR es permitir que varios idiomas utilicen la misma infraestructura básica, un sistema de estilo DFM habría tenido mucho sentido.
Extensibilidad
Una clase de administrador de imágenes que escribí se puede proporcionar con una fuente de datos (como una ruta a sus archivos de imagen) y luego cargar nuevos objetos de imagen automáticamente si intenta recuperar un nombre que no está en la colección pero que está disponible en la fuente de datos. Tiene una variable de clase escrita como class of
la clase de imagen base, que representa la clase de cualquier objeto nuevo que se cree. Viene con un valor predeterminado, pero hay algunos puntos, cuando se crean nuevas imágenes con fines especiales, que las imágenes deben configurarse de diferentes maneras. (Creándolo sin un canal alfa, recuperando metadatos especiales de un archivo PNG para especificar el tamaño del sprite, etc.)
Esto podría hacerse escribiendo grandes cantidades de código de configuración y pasando opciones especiales a todos los métodos que podrían terminar creando un nuevo objeto ... o simplemente podría hacer una subclase de la clase de imagen base que anula un método virtual donde el aspecto en cuestión se configura y luego usa un bloque try / finally para reemplazar temporalmente la propiedad "clase predeterminada" según sea necesario y luego restaurarla. Hacerlo con variables de referencia de clase es mucho más simple y no es algo que podría hacerse con genéricos.
fuente
TClass
es útil, con algún código de muestra? En mi investigación superficial sobre InternetTClass
, descubro queTClass
se puede pasar como un parámetro. Esto se hace en .NET usando Generics. Los métodos de fábrica simplemente se marcanstatic
en .NET y no requieren una instancia de clase para ejecutarse.TClass
es una característica fundamental del lenguaje que requiere soporte del compilador. No puede "escribir el suyo" sin escribir su propio lenguaje, y para .NET incluso eso no sería suficiente porque el modelo de objetos está definido por el CLR, no por los idiomas individuales. Es algo que literalmente necesita ser parte del marco .NET en sí, o no puede existir.Respuestas:
.NET (CLR) fue la tercera generación del Modelo de objetos componentes (COM) de Microsoft, que en los primeros días se denominaba "tiempo de ejecución COM +". Microsoft Visual Basic y el mercado de controles COM / ActiveX ha tenido mucha más influencia en las opciones específicas de compatibilidad arquitectónica CLR que Borland Delphi. (Es cierto que el hecho de que Delphi haya adoptado los controles ActiveX ciertamente ayudó a hacer crecer el ecosistema ActiveX, pero COM / ActiveX existía antes de Delphi)
La arquitectura de COM se desarrolló en C (no en C ++) y se centró en las interfaces, en lugar de las clases. Además, admite la composición de objetos, lo que significa que un objeto COM podría estar compuesto de varios objetos diferentes, con la interfaz IUnknown uniéndolos. Pero IUnknown no tuvo ningún papel en la creación de objetos COM, que fue diseñado para ser lo más independiente posible del lenguaje. La creación de objetos fue manejada generalmente por IClassFactory, y la reflexión por ITypeLibrary y las interfaces relacionadas. Esta separación de preocupaciones fue independiente del lenguaje de implementación, y las características de cada interfaz COM básica se mantuvieron mínimas y ortogonales.
Entonces, como resultado de la popularidad de los controles COM y ActiveX, la arquitectura .NET se creó para admitir COM IUnknown, IClassFactory e ITypeLibrary. En COM, estas interfaces no estaban necesariamente en el mismo objeto, por lo que agruparlas no necesariamente tenía sentido.
fuente