c# - tipos - Clase interna de instanciación con constructor privado.
tipos de constructores (5)
Estoy tratando de usar la reflexión para crear una instancia de una clase. Pero está sellado interno y tiene constructor privado. Me pregunto cómo puedo iniciarlo y, como parte del marco, solo puedo usar la reflexión para sacarlo.
internal sealed class ABC
{
private ABC(string password){}
public static ABC Create(string password){};
}
Agregado: System.ServiceModel.Channels.SelfSignedCertificate es la clase interna que estoy tratando de usar
EDITAR: No me había dado cuenta de que mencionó que el tipo que está intentando inicializar es parte del marco .NET. Pensé que era uno de tus propios tipos, solo referenciado desde otro lugar.
Le ruego encarecidamente que no intente esto . Microsoft está perfectamente en libertad de cambiar o eliminar clases internas entre las versiones de la infraestructura: su código será increíblemente frágil si confía en detalles de implementación como este.
Cambia tu diseño para evitar tener que hacer esto.
Respuesta original:
Sí, tendrías que usar la reflexión, así:
using System;
using System.Reflection;
internal sealed class ABC
{
private ABC(string password)
{
Console.WriteLine("Constructor called");
}
}
public class Test
{
static void Main()
{
ConstructorInfo ctor = typeof(ABC).GetConstructors
(BindingFlags.Instance | BindingFlags.NonPublic)[0];
ABC abc = (ABC) ctor.Invoke(new object[] { "test" });
}
}
Tenga en cuenta que violar los modificadores de acceso de esta manera requiere el permiso ReflectionPermissionFlag.MemberAccess
. Si sabe que habrá un método estático llamado Create
, sería mejor invocarlo a través de la reflexión:
using System;
using System.Reflection;
internal sealed class ABC
{
private ABC(string password)
{
Console.WriteLine("Constructor called");
}
public static ABC Create(string password)
{
return new ABC(password);
}
}
public class Test
{
static void Main()
{
MethodInfo method = typeof(ABC).GetMethod("Create",
BindingFlags.Static | BindingFlags.Public);
ABC abc = (ABC) method.Invoke(null, new object[]{"test"});
}
}
En primer lugar, el hecho mismo de que sea interno significa que no debe hacer lo que quiere hacer.
Debería intentar seriamente encontrar una ruta alternativa a lo que quiere lograr.
Desafortunadamente, no nos dices lo que quieres lograr, solo el próximo paso que crees que quieres hacer, por lo que puedo ayudarte.
Este código funcionará y accederá al método estático público:
Type t = typeof(SomeOtherTypeInSameAssembly)
.Assembly.GetType("ClassLibrary1.ABC");
MethodInfo method = t.GetMethod("Create",
BindingFlags.Public | BindingFlags.Static, null,
new Type[] { typeof(String) },
new ParameterModifier[0]);
Object o = method.Invoke(null, new Object[] { "test" });
Tenga en cuenta que esto depende de tener acceso a otro tipo en el mismo ensamblaje, que es público. Si no tiene eso, necesita obtener el objeto Assembly que contiene el tipo.
No puede instanciar clases con constructores privados a menos que sea una clase anidada.
http://msdn.microsoft.com/en-us/library/kcfb85a6%28VS.71%29.aspx
Si es internal
a un ensamblaje que no es tuyo y el constructor está marcado como private
, el autor del ensamblaje está tratando de evitar que crees el objeto.
Lo siguiente es realmente malo, ya que depende de clases y métodos no públicos que podrían cambiar sin previo aviso.
Agregado:
System.ServiceModel.Channels.SelfSignedCertificate
es la claseinternal
que estoy tratando de usar
No hagas esto El marco puede cambiar debajo de ti en un abrir y cerrar de ojos arruinando tu código y todo tu trabajo duro.
Dicho esto, podrías hacer esto:
MethodInfo method = Type.GetType(assemblyQualifiedName).GetMethod("Create");
ABC o = (ABC)method.Invoke(null, new[] { "test" });
Esto invoca el método static
Create
. Otra opcion es
MethodInfo method = Type.GetType(assemblyQualifiedName).GetConstructor(
BindingFlags.NonPublic | BindingFlags.Instance,
null,
new[] { typeof(string) },
null
);
ABC o = (ABC)method.Invoke(new[] { "test" });
que utiliza la reflexión para cargar el constructor que acepta una string
como parámetro.
Una forma fácil de obtener el nombre calificado para el montaje es
string name = typeof(somePublicType).Assembly.GetType("Namespace.ABC");
donde somePublicType
es un tipo que es público y en el mismo ensamblado que ABC
.
Usa la clase Activator para crear instancias.
Activator.CreateInstance(myType, true);