2009-05-28 6 views
72

Mając zespół, który nie może modyfikować (sprzedawca-zestawie), które mają metodę zwrócenie obiektu typ ale jest naprawdę typu wewnętrznego.C# - Jak uzyskać dostęp do wewnętrznego klasy z zespołu zewnętrznego

Jak uzyskać dostęp do pól i/lub metod obiektu z mojego zespołu?

Należy pamiętać, że nie można zmodyfikować zestawu dostarczonego przez dostawcę.

W istocie, oto co mam:

Od producenta:

internal class InternalClass 
    public string test; 
end class 

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

Z mojego zespołu za pomocą zespołu sprzedawca.

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

Odpowiedz

70

Bez dostępu do typu (a nie „InternalsVisibleTo” etc) byś użyć refleksji. Ale lepszym pytaniem byłby: powinien uzyskać dostęp do tych danych przez? To nie jest część kontraktu typu publicznego ... brzmi dla mnie tak, jakby miał być traktowany jako nieprzejrzysty obiekt (dla swoich celów, nie twój).

Opisałeś to jako publiczne pole instancji; aby uzyskać to poprzez refleksję:

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

Jeśli to jest rzeczywiście właściwością (nie pole):

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

Jeśli jest niepubliczna, musisz użyć BindingFlags przeciążenie GetField/GetProperty.

Ważny na bok: uważaj z takim odbiciem; implementacja może ulec zmianie w następnej wersji (złamanie kodu) lub może zostać zaciemniona (zerwanie kodu) lub może nie mieć wystarczającego "zaufania" (złamanie kodu). Czy dostrzegasz wzór?

+1

Wooo .. 2 minuty! Było blisko! Dobrze powiedział Marc (jak zawsze). : D – Galilyou

+0

Świetnie! To działa. Myślałem, że nie mogę uzyskać dostępu do internals w ten sposób ... Dziękuję bardzo –

+0

Marc Zastanawiam się ... możliwe jest uzyskanie dostępu do prywatnych pól/właściwości, ale czy istnieje sposób na obsłużenie obiektu zwróconego przez GetValue przy użyciu odpowiedniego typu? – codingadventures

-3

Cóż, nie możesz. Klasy wewnętrzne nie mogą być widoczne poza ich złożeniem, więc nie ma wyraźnego sposobu na bezpośredni dostęp do nich - oczywiście AFAIK. Jedynym sposobem jest użycie późnego wiązania w środowisku wykonawczym za pomocą refleksji, wówczas można wywoływać metody i właściwości z klasy wewnętrznej pośrednio.

+0

Rozwiązanie zonkflut zadziałało dla mnie w przeszłości – phlip

+0

chociaż polega na edytowaniu wywoływanego zestawu – phlip

+4

Możesz wywoływać wszystko z odbiciem –

3

Odbicie.

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

Korzystaj z zasilania mądrze. Nie zapominaj o sprawdzaniu błędów. :)

171

Widzę tylko jeden przypadek, który pozwoliłby na wystawienie twoich wewnętrznych członków na inne zgromadzenie i to jest do celów testowych.

Mówiąc, że istnieje sposób, aby umożliwić „przyjaciel” zespoły dostęp do wewnętrznych:

w pliku AssemblyInfo.cs projektu dodać linię dla każdego zespołu.

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

ta informacja jest dostępna here.

Nadzieja to pomaga.

+1

Właśnie dzisiaj wyszukałem screencst i słyszałem o odsłonięciu wewnętrznych członków danego zespołu, tak aby inny (test montaż) ma dostęp do niego, ale nie miał pojęcia, jak to zrobić. Dziękujemy! –

+3

Głosujcie, ponieważ to była dla mnie przydatna informacja ... chociaż nie może to być odpowiedź na pytanie: - D – yeyeyerman

+4

pytanie mówi, że nie można zmodyfikować zespołu partnerów. Głosowanie. – danielpops

3

Chciałbym argumentować jeden punkt - że nie można powiększyć oryginalnego zestawu - przy użyciu Mono.Cecil można wstrzyknąć [InternalsVisibleTo(...)] do zespołu 3pty. Pamiętaj, że mogą być konsekwencje prawne - masz kłopot z montażem 3pty i implikacjami technicznymi - jeśli zespół ma mocną nazwę, musisz go usunąć lub ponownie podpisać innym kluczem.

Install-Package Mono.Cecil 

I kod jak:

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

Dla mnie, nie można go zmodyfikować, oznacza, że ​​pochodzi z nugetu i nie chcę tworzyć lokalnego nugetu z modyfikacjami ani nim zarządzać. Dla niektórych osób utrata silnej nazwy będzie miała znaczenie. Ale jest to interesujący punkt. – binki