2013-01-03 5 views
5

Ich habe eine Engine erstellt, die Plugins von Drittanbietern (DLLs) akzeptiert, die eine Schnittstelle implementieren.Ist es möglich, eine Instanz einer Klasse zu erstellen, ohne irgendeinen Code von der Klasse auszuführen? (keine Ctor, keine Feldinitialisierungen)

Da ich keine Kontrolle über den Code habe, der eingesteckt wird, möchte ich in der Lage sein, eine bestimmte Methode (von der Schnittstelle) von der richtigen Klasse auszuführen (GetTypes-Schleife, bis ich die Interface-Klasse finde).

Da jeder kann schön Konstruktorcode erstellen, die auf Activator.CreateInstance ausführt, kann ich das lösen von FormatterServices.GetUninitializedObject verwenden. Aber das hilft nicht, wenn Code für Felder in der Klasse initialisiert wird.

public class myclass : myinterface { 

    public someotherclass name = new someotherclass() 

    public myclass() { 
    //Unknown code 
    } 

    //I only want this run. 
    public string MyProperty{ 
    get { 
     return "ANiceConstString"; 
    } 
    } 
} 

Das Problem mit beiden Möglichkeiten (CreateInstance/GetUninitializedObject) ist, dass der Konstruktor von someotherclass wird ausgeführt werden.

Bevor Sie beginnen, analysieren meine Bedürfnisse. Dies wird nur bei der Initialisierung der Engine ausgeführt, um eine Reihe von Standardwerten zu erhalten. Wenn dieses get'er auf anderen initialisierten Werten beruht, wird das "plugin" als fehlgeschlagen markiert, da kein gültiger Wert zurückgegeben wird. Wenn nicht als fehlgeschlagen gekennzeichnet, wird die Klasse später ordnungsgemäß mit Activator.CreateInstance() geladen.

Also bleiben Sie bei dieser Frage: Unterstützt .Net jede Möglichkeit, eine 100% nicht initialisierte Klasse zu erstellen?

Update für die Antworten. Ich habe das getestet, bevor ich meine Frage gestellt habe.

Für die Antwort, dass einige Klasse nicht laufen wird, habe ich bereits getestet, und es wird ausgeführt, wenn statisch.

public class myclass : myinterface { 

    static Tutle test; 

    public myclass() { 
     test = new Tutle(); 
    } 

    public class Tutle { 
     public Tutle() { 
      MessageBox.Show("RUN!"); 
     } 
    } 
} 

CreateInstance zeigt die Messagebox an. GetUninitializedObject nicht.

public class myclass : myinterface { 

    static Tutle test = new Tutle(); 

    public myclass() { 
    } 

    public class Tutle { 
     public Tutle() { 
      MessageBox.Show("RUN!"); 
     } 
    } 
} 

CreateInstance zeigt die Messagebox an. GetUninitializedObject zeigt die Nachrichtenbox an.

Gibt es eine Möglichkeit, statische Feldinitiatoren und -tore zu umgehen?

+0

Wenn Sie wirklich nicht, eine Objektinstanz erstellt werden soll, es klingt wie Sie stattdessen eine * statische * Eigenschaft möchten. Ja, es bedeutet, dass Sie es nicht in einer Schnittstelle angeben müssen ... aber Sie verwenden bereits eine Reflexion, so dass Sie einfach überprüfen können, ob alle Typen die entsprechende Eigenschaft besitzen. Oder wenn Sie wissen, dass der Eigenschaftswert immer eine Konstante sein soll, benötigen Sie stattdessen möglicherweise ein benutzerdefiniertes Attribut. –

+2

Wenn Sie keine Kontrolle über den Code haben, der ausgeführt wird, können Sie in Erwägung ziehen, diesen Code in einer separaten Anwendungsdomäne mit eingeschränkten Berechtigungen auszuführen. Dies könnte eine Alternative zum Erstellen eines nicht initialisierten Objekts sein. –

Antwort

14

einfach:

var obj = (myclass)FormatterServices.GetUninitializedObject(typeof(myclass)); 

Das nicht den Konstruktor/Feld Initialisierungen ausgeführt werden. Überhaupt. Es wird nicht führen Sie den Konstruktor für someotherclass; name wird null sein.

Es wird jedoch alle statischen Konstruktor ausgeführt, die gegebenenfalls unter Standard-.NET-Regeln vorhanden ist.

JEDOCH! Ich sollte beachten, dass diese Methode nicht für Ad-hoc-Nutzung gedacht ist; Seine primäre Absicht ist die Verwendung in Serializern und Remoting-Engines. Es besteht eine sehr gute Chance, dass die Typen nicht korrekt funktionieren, wenn sie auf diese Weise erstellt werden, wenn Sie anschließend keine Schritte unternommen haben, um sie wieder in einen gültigen Zustand zu versetzen (was jede Serialisierungs-/Remoting-Engine sicher tun würde).

+1

Korrekt, der Feldinitialisierer ('public someotherclass name = new someotherclass();' in Ihrem Beispiel) wird * nicht * ausgeführt. –

+0

Überprüfen Sie mein Update. GetUninitializedObject führt den Code aus ... Bereits vor der Veröffentlichung getestet. NM. Statisch war das Problem. Also keine Möglichkeit statisch herumzukommen? – Wolf5

+1

@ Wolf5 Ich testete auch, p und no: es ist nicht (bearbeiten: dieser Kommentar ist jetzt veraltet, da es jetzt markiert ist statisch) –

5

Als Alternative Gestaltungsüberlegung:

[SomeFeature("ANiceConstString")] 
public class myclass : myinterface { 

    public someotherclass name = new someotherclass() 

    public myclass() { 
    //Unknown code 
    } 
} 

Jetzt können Sie die Funktion ohne Instanziierung zuzugreifen; nur verwenden:

var attrib = (SomeFeatureAttribute)Attribute.GetCustomAttribute(
    type, typeof(SomeFeatureAttribute)); 
string whatever = attrib == null ? null : attrib.Name; 

mit:

[AttributeUsage(
    AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum)] 
public sealed class SomeFeatureAttribute : Attribute 
{ 
    private readonly string name; 
    public string Name { get { return name; } } 
    public SomeFeatureAttribute(string name) { this.name = name; } 
} 
+0

Danke. Ich denke, ich werde das hinzufügen. Da die Schnittstelle veröffentlicht und festgelegt ist, kann ich eine Vorprüfung durchführen, wenn das Attribut festgelegt ist, und diese vor dem Erstellen einer Instanz verwenden. Rückwärtskompatibilität. – Wolf5

+0

Ich mag das viel besser. 'GetUninitializedObject' klingt sehr gefährlich! –

Verwandte Themen