30 Stimmen

Instanziierung einer internen Klasse mit privatem Konstruktor

Ich versuche, Reflection zu verwenden, um eine Instanz einer Klasse zu erstellen. Aber es ist intern versiegelt und hat private Konstruktor. Ich frage mich, wie kann ich es initiaise und wie sein Teil des Rahmens, ich kann nur Reflexion verwenden, um es herauszunehmen?

internal sealed class ABC
{
    private ABC(string password){}
    public static ABC Create(string password){};
}

Hinzugefügt: System.ServiceModel.Channels.SelfSignedCertificate ist die interne Klasse, die ich zu verwenden versuche

1 Stimmen

Sie möchten den privaten Konstruktor oder die statische Create-Methode aufrufen?

0 Stimmen

Es handelt sich um eine interne Klasse im Framework mit obiger Struktur. Ich möchte eine Instanz der Klasse mithilfe eines Konstruktors/einer statischen Methode erstellen und danach die MethodInfo verwenden, um die Methoden in der Klasse zu verwenden. object mc = assembly.CreateInstance( ---- <- kann es nicht verwenden, da es einen privaten Konstruktor hat MethodInfo mi = type1.GetMethod( "MyMethod", bf );

30voto

Jon Skeet Punkte 1325502

EDIT: Ich hatte nicht bemerkt, dass Sie erwähnt haben, dass der Typ, den Sie zu initialisieren versuchen, Teil des .NET Frameworks ist. Ich dachte, es war einer Ihrer eigenen Typen, nur von anderswo referenziert.

Ich möchte Ihnen dringend raten dies nicht zu versuchen . Microsoft steht es vollkommen frei, interne Klassen zwischen den Releases des Frameworks zu ändern oder zu entfernen - Ihr Code wird unglaublich brüchig, wenn Sie sich auf solche Implementierungsdetails verlassen.

Ändern Sie Ihr Design, damit Sie dies nicht tun müssen.


Ursprüngliche Antwort:

Ja, Sie müssen eine Reflexion verwenden - etwa so:

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" });
    }
}

Beachten Sie, dass die Verletzung von Zugriffsmodifikatoren auf diese Weise die ReflectionPermissionFlag.MemberAccess Erlaubnis. Wenn Sie wissen, dass es eine statische Methode namens Create wären Sie besser beraten, wenn Sie dass durch Reflexion:

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"});
    }
}

2 Stimmen

Wenn der ABC-Typ in einer anderen Baugruppe intern ist, muss er den Typ über seinen FullName abrufen.

0 Stimmen

Vielen Dank an alle für ihre Kommentare. Ich werde einen anderen Weg finden, dies zu tun. Es ist ein guter Punkt, dass MS es ändern kann! Nochmals vielen Dank

25voto

Lasse V. Karlsen Punkte 364542

Zunächst einmal bedeutet die Tatsache, dass es sich um eine interne Angelegenheit handelt, dass Sie nicht das tun sollen, was Sie tun wollen.

Sie sollten ernsthaft versuchen, einen alternativen Weg zu dem zu finden, was Sie erreichen wollen.

Leider sagen Sie uns nicht, was Sie erreichen wollen, sondern nur den nächsten Schritt, den Sie zu tun gedenken, und dabei kann ich Ihnen helfen.

Dieser Code funktioniert und greift auf die öffentliche statische Methode zu:

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" });

Beachten Sie, dass dies nur möglich ist, wenn Sie Zugriff auf einen anderen Typ in derselben Assembly haben, der öffentlich ist. Ist dies nicht der Fall, müssen Sie auf das Assembly-Objekt zugreifen, das den Typ enthält.

10 Stimmen

First of all, the very fact that it is internal means you're not supposed to be doing what you want to do. was über die Herstellung einer Einheit Tests, sondern halten die Klasse Isolation?

24 Stimmen

Allein die Tatsache, dass jemand auf interne Klassen zugreifen muss und sich über bestimmte interne Klassen im Klaren ist, zeigt, dass er wahrscheinlich intelligent genug ist, Reflector zu öffnen und selbst zu entscheiden, ob dies nützlich oder eine gute Idee ist. Code ist Code, und ein "interner" Modifikator ist nichts anderes als eine Art DRM, das umgangen werden soll, IMO.

4 Stimmen

@ktutnik: Bei Unit-Tests wird dies in der Regel erreicht durch InternalsVisibleToAttribute

5voto

jason Punkte 227577

Wenn es internal zu einer Baugruppe, die nicht die Ihre ist, und der Konstruktor ist markiert als private ist der Autor der Baugruppe sehr bemüht, Sie von der Erstellung des Objekts abzuhalten.

Das Folgende ist wirklich böse, da Sie sich auf nicht-öffentliche Klassen und Methoden verlassen, die sich ohne Vorankündigung ändern können.

Hinzugefügt: System.ServiceModel.Channels.SelfSignedCertificate ist die internal Klasse, die ich zu verwenden versuche

Tun Sie dies nicht . Der Rahmen kann sich im Handumdrehen ändern und Ihren Code und all Ihre harte Arbeit ruinieren.

Das heißt, Sie könnten dies tun:

MethodInfo method = Type.GetType(assemblyQualifiedName).GetMethod("Create");
ABC o = (ABC)method.Invoke(null, new[] { "test" });

Dies ruft die static Methode Create . Eine andere Möglichkeit ist

MethodInfo method = Type.GetType(assemblyQualifiedName).GetConstructor(
                        BindingFlags.NonPublic | BindingFlags.Instance,
                        null,
                        new[] { typeof(string) },
                        null
                    );
ABC o = (ABC)method.Invoke(new[] { "test" });

die Reflexion verwendet, um den Konstruktor zu laden, der eine string als Parameter.

Ein einfacher Weg, den assembly-qualifizierten Namen zu erhalten, ist

string name = typeof(somePublicType).Assembly.GetType("Namespace.ABC");

donde somePublicType ist ein Typ, der öffentlich ist und sich in der gleichen Baugruppe befindet wie ABC .

0 Stimmen

Ich habe keinen Zugriff auf ABC und kann daher MethodInfo method = typeof(ABC) nicht verwenden. Ich habe Reflektor verwendet und diese Klasse im Framework gesehen. Ich muss sie verwenden.

0 Stimmen

Wenn der Entwickler des Frameworks gewollt hätte, dass die Klasse von den Nutzern des Frameworks verwendet wird, gäbe es eine andere Möglichkeit, eine Instanz des Objekts zu erhalten, ohne auf diese Art von Hackerei zurückzugreifen.

0 Stimmen

@unbekannt(google): Sie müssen den assembly-qualifizierten Namen verwenden. Siehe meine Bearbeitung.

1voto

jjacka Punkte 513

Verwenden Sie die Klasse Activator, um sie zu instanziieren

Activator.CreateInstance(myType, true);

0 Stimmen

Fehler: Die Datei oder Assembly 'System.ServiceModel.Channels' oder eine ihrer Abhängigkeiten konnte nicht geladen werden. Das System kann die angegebene Datei nicht finden.

0 Stimmen

Activator.CreateInstance(internalType, new object[] {null, null}) In meinem Fall nimmt der Konstruktor 2 Parameter. Es funktioniert für mich.

-1voto

Brett Bim Punkte 3024

Sie können keine Klassen mit privaten Konstruktoren instanziieren, es sei denn, es handelt sich um eine verschachtelte Klasse.

http://msdn.microsoft.com/en-us/library/kcfb85a6%28VS.71%29.aspx

0 Stimmen

Stimmt nicht, mit Reflexion ist alles möglich, wenn man genug Rechte hat.

0 Stimmen

Aber haben Sie genug Rechte, wenn die Klasse intern versiegelt ist?

0 Stimmen

Sie können sie innerhalb der Klasse mit einer statischen Methode instanziieren.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X