tipos - que es una instancia en c#
Crear instancia de objeto sin invocar constructor? (11)
En C #, ¿hay alguna manera de instanciar una instancia de una clase sin invocar a su constructor?
Supongamos que la clase es pública y está definida en una biblioteca de terceros y el constructor es interno. Las razones por las que quiero hacer esto son complicadas, pero sería útil saber si es posible usar algún tipo de hackeo de C #.
NOTA: específicamente no quiero llamar a ningún constructor, por lo que no es una opción usar el reflejo para acceder al constructor interno.
Contrariamente a lo que muchos creen, un constructor no tiene mucho que ver con la instanciación de un objeto en absoluto (término bastante engañoso). Un constructor es un método especial que se puede invocar después de la instanciación de un objeto para permitir que ese objeto se inicialice correctamente. En C ++, la instanciación de objetos asigna memoria para el objeto, en .NET y Java se asigna y preinicializa a valores predeterminados dependiendo del tipo de campos (0, nulo, falso, etc.). Luego, el tiempo de ejecución llama al constructor. El nuevo operador encapsula estas dos acciones separadas en lo que parece ser una sola operación. La deserialización nunca pudo haber funcionado en .NET si no fue posible crear una instancia sin usar un constructor. Dicho esto, el llamado tipo ConstructorInfo actúa como un nuevo operador y constructor cuando llama a su método Invoke (...).
EDITAR: Has actualizado tu pregunta, quieres construir una clase sin un constructor. O llame a un "Constructor vacío" predeterminado.
Esto no se puede hacer, ya que el compilador no generará un constructor predeterminado si ya hay uno especificado. Sin embargo, para beneficio de los lectores, aquí se explica cómo acceder a un constructor interno, protegido o privado:
Suponiendo que tu clase se llama Foo:
using System.Reflection;
// If the constructor takes arguments, otherwise pass these as null
Type[] pTypes = new Type[1];
pTypes[0] = typeof(object);
object[] argList = new object[1];
argList[0] = constructorArgs;
ConstructorInfo c = typeof(Foo).GetConstructor
(BindingFlags.NonPublic |
BindingFlags.Instance,
null,
pTypes,
null);
Foo foo =
(Foo) c.Invoke(BindingFlags.NonPublic,
null,
argList,
Application.CurrentCulture);
Feo, pero funciona
Por supuesto, puede haber una razón perfectamente legítima para marcar a un constructor como interno, por lo que realmente debería considerar la logística de lo que desea antes de abusar de esa clase si lo hace reflexionando.
En realidad, parece que hicieron el constructor interno solo para que no puedas instanciarlo. Puede tener un constructor o un método de fábrica.
Mira estos artículos:
Prevenir la derivación de terceros: parte 1
Prevenir la derivación de terceros: parte 2
ellos tipo de explicar el razonamiento.
Lo que está pidiendo hacer es una violación de la filosofía sobre la cual se desarrolló la programación administrada. .Net Framework y C # están construidos con el principio de que, siempre que sea posible, los objetos deben abstraerse de su memoria subyacente. Los objetos son objetos, no una matriz estructurada de bytes. Esta es la razón por la cual no puedes lanzar objetos a punteros vacíos de cualquier manera. Cuando los objetos se abstraen de su memoria subyacente, es fundamentalmente inválido sugerir que una instancia de objeto puede existir sin invocar al constructor.
Dicho esto, el framework .Net ha hecho concesiones al hecho de que, en realidad, los objetos están realmente representados en la memoria. Con algo de creatividad, es posible crear instancias de tipos de valores sin invocar sus inicializadores. Sin embargo, si sientes que debes hacerlo, probablemente estés haciendo las cosas mal.
Nadie aquí ha aclarado lo que significa "No se puede hacer".
El constructor es lo que crea el objeto. Su pregunta es similar a "¿Cómo puedo construir un castillo de arena sin darle forma como un castillo?" No puedes - Todo lo que tendrás es un montón de arena.
Lo más cercano que podrías hacer es asignar un bloque de memoria del mismo tamaño que tu objeto:
byte[] fakeObject = new byte[sizeof(myStruct)];
(NOTA: incluso eso solo funcionará en MyStruct es un tipo de valor)
No he intentado esto, pero hay un método llamado FormatterServices.GetUninitializedObject que se usa durante la deserialización.
Las observaciones de MSDN dicen:
Debido a que la nueva instancia del objeto se inicializa a cero y no se ejecutan constructores, es posible que el objeto no represente un estado considerado válido por ese objeto.
Noté la "muerte" del tema, pero solo para aclarar a otros lectores y para dar una respuesta final que tal vez no fue posible cuando se publicó la pregunta. Aquí va.
Parece que puede instanciar una clase sin usar sus constructores asignando valores a sus propiedades. Aquí está la dirección donde está el instructivo en MSDN para este tipo de creación de instancias http://msdn.microsoft.com/en-us/library/bb397680.aspx .
Parece que esta es una técnica que no se conoce bien porque la encontré en un artículo en CodeProject y luego en Google y no encontré nada al respecto y luego visité MSDN Homepage y hubo una publicación que me vinculó a esa exacta tema. Parece que es un tema desconocido en lugar de uno nuevo porque la fecha en la publicación de CodeProject data de mayo de 2008.
Espero que esto ayude a alguien más a que google sea así y se presente con esta pregunta.
Podría ser posible acceder al constructor a través de la reflexión e invocarlo así (pero no estoy seguro de que funcione, ya que el constructor es interno, tendrás que probarlo). De lo contrario, que yo sepa, no puede crear un objeto sin llamar al constructor.
Si la clase (y las clases de objetos a los que hace referencia) es Serializable, puede crear una copia profunda mediante serialización utilizando un BinaryFormatter que se envía a un MemoryStream (creando un byte de matriz de bytes []), luego deserializando. Vea las respuestas a esta pregunta sobre la conversión de un objeto a una matriz de bytes . (Pero tenga en cuenta: guardar la matriz de bytes para usar más tarde / en otro lugar probablemente no funcione. IOW no guarda la matriz de bytes en un archivo u otra forma persistente).
Tienes que llamar a un constructor para crear un objeto. Si no hay ninguno disponible a su gusto, tal vez podría usar una biblioteca de reescritura de código de bytes como Cecil del proyecto Mono. Funciona tanto en Windows como en Linux. De algunas de las demos que vi, se veía bastante genial. Puede cambiar los niveles de protección de métodos y todo tipo de cosas locas.
Ver la función System.Activator.CreateInstance.