Frage C # - Wie man von einer externen Baugruppe auf die interne Klasse zugreift


Ich habe eine Assembly, die ich nicht modifizieren kann (vom Hersteller geliefert), die eine Methode hat, die eine zurückgibt Objekt Typ aber ist wirklich von einem internen Typ.

Wie kann ich von meiner Assembly auf die Felder und / oder Methoden des Objekts zugreifen?

Beachten Sie, dass ich die vom Lieferanten bereitgestellte Assembly nicht ändern kann.

Im Wesentlichen, hier ist, was ich habe:

Vom Verkäufer:

internal class InternalClass
  public string test;
end class

public class Vendor
  private InternalClass _internal;
  public object Tag {get{return _internal;}}
end class

Von meiner Assembly, die die Herstellerassembly verwendet.

public class MyClass
{
  public void AccessTest()
  {
    Vendor vendor = new Vendor();
    object value = vendor.Tag;
    // Here I want to access InternalClass.test
  }
}

75
2018-05-28 13:27


Ursprung


Antworten:


Ohne Zugriff auf den Typ (und keine "InternalsVisibleTo" usw.) müssten Sie Reflexion verwenden. Aber eine bessere Frage wäre: sollte Sie greifen auf diese Daten zu? Es ist nicht Teil des öffentlichen Vertrags ... es klingt für mich so, als ob es als undurchsichtiges Objekt behandelt werden soll (für ihre Zwecke, nicht für Ihre Zwecke).

Sie haben es als öffentliches Instanzfeld beschrieben. um dies durch Reflexion zu bekommen:

object obj = ...
string value = (string)obj.GetType().GetField("test").GetValue(obj);

Wenn es sich tatsächlich um eine Eigenschaft (kein Feld) handelt:

string value = (string)obj.GetType().GetProperty("test").GetValue(obj,null);

Wenn es nicht öffentlich ist, müssen Sie das verwenden BindingFlags Überlastung von GetField/GetProperty.

Wichtig beiseite: Sei vorsichtig mit der Reflexion so; Die Implementierung könnte sich in der nächsten Version ändern (Ihren Code zu knacken), oder sie könnte verschleiert werden (Ihren Code zu knacken), oder Sie haben möglicherweise nicht genug "Vertrauen" (brechen Sie Ihren Code). Siehst du das Muster?


74
2018-05-28 13:32



Ich sehe nur einen Fall, in dem Sie Ihre internen Mitglieder einer anderen Assembly aussetzen würden, und zwar zu Testzwecken.

Sagen wir, dass es eine Möglichkeit gibt, "Freund" -Assemblies Zugriff auf Interna zu gewähren:

In der AssemblyInfo.cs-Datei des Projekts fügen Sie eine Zeile für jede Assembly hinzu.

[assembly: InternalsVisibleTo("name of assembly here")]

Diese Information ist verfügbar Hier.

Hoffe das hilft.


181
2018-06-12 00:52



Betrachtung.

using System.Reflection;

Vendor vendor = new Vendor();
object tag = vendor.Tag;

Type tagt = tag.GetType();
FieldInfo field = tagt.GetField("test");

string value = field.GetValue(tag);

Verwenden Sie die Macht mit Bedacht. Vergessen Sie nicht die Fehlerüberprüfung. :)


3
2018-05-28 13:34



Ich möchte einen Punkt argumentieren - dass Sie die ursprüngliche Assemblierung nicht erweitern können - mit Mono.Cecil können Sie injizieren [InternalsVisibleTo(...)] bis zur 3. Montage. Beachten Sie, dass es rechtliche Konsequenzen geben kann - Sie haben Probleme mit der Assembly und den technischen Implikationen - wenn die Assembly einen starken Namen hat, müssen Sie sie entweder entfernen oder mit einem anderen Schlüssel neu signieren.

 Install-Package Mono.Cecil

Und der Code mag:

static readonly string[] s_toInject = {
  // alternatively "MyAssembly, PublicKey=0024000004800000... etc."
  "MyAssembly"
};

static void Main(string[] args) {
  const string THIRD_PARTY_ASSEMBLY_PATH = @"c:\folder\ThirdPartyAssembly.dll";

   var parameters = new ReaderParameters();
   var asm = ModuleDefinition.ReadModule(INPUT_PATH, parameters);
   foreach (var toInject in s_toInject) {
     var ca = new CustomAttribute(
       asm.Import(typeof(InternalsVisibleToAttribute).GetConstructor(new[] {
                      typeof(string)})));
     ca.ConstructorArguments.Add(new CustomAttributeArgument(asm.TypeSystem.String, toInject));
     asm.Assembly.CustomAttributes.Add(ca);
   }
   asm.Write(@"c:\folder-modified\ThirdPartyAssembly.dll");
   // note if the assembly is strongly-signed you need to resign it like
   // asm.Write(@"c:\folder-modified\ThirdPartyAssembly.dll", new WriterParameters {
   //   StrongNameKeyPair = new StrongNameKeyPair(File.ReadAllBytes(@"c:\MyKey.snk"))
   // });
}

3
2018-06-02 13:03



Nun, du kannst nicht. Interne Klassen können nicht außerhalb ihrer Assembly sichtbar sein, also keine explizite Möglichkeit, direkt auf -AFAIK zuzugreifen. Die einzige Möglichkeit besteht darin, die späte Laufzeitbindung über Reflektion zu verwenden. Anschließend können Sie Methoden und Eigenschaften der internen Klasse indirekt aufrufen.


-3
2018-05-28 13:34