Bir dış derlemeden dahili bir sınıfa nasıl erişebilirim?


97

Değiştiremediğim (satıcı tarafından sağlanan), bir nesne türünü döndüren bir yönteme sahip, ancak gerçekten dahili bir tür olan bir derlemeye sahip olmak .

Nesnenin alanlarına ve / veya yöntemlerine montajımdan nasıl erişebilirim?

Satıcı tarafından sağlanan derlemeyi değiştiremeyeceğimi unutmayın.

Temelde, işte sahip olduğum şey:

Satıcıdan:

internal class InternalClass
  public string test;
end class

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

Satıcı montajını kullanarak montajımdan.

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

Yanıtlar:


83

Türüne erişim olmadan (ve "InternalsVisibleTo" vb. Olmadan) yansımayı kullanmanız gerekir. Ama daha iyi bir soru olurdu: edilmelidir Bu verileri erişiyor? Kamu tipi sözleşmenin bir parçası değil ... bana sanki opak bir nesne olarak görülmesi amaçlanıyor gibi geliyor (sizin amaçları için değil, onların amaçları için).

Bunu genel bir örnek alanı olarak tanımladınız; bunu yansıtma yoluyla elde etmek için:

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

Gerçekte bir mülkse (bir alan değilse):

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

Halka açık değilse BindingFlags, GetField/ aşırı yüklemesini kullanmanız gerekir GetProperty.

Bir kenara önemli : böyle düşünürken dikkatli olun; uygulama sonraki sürümde değişebilir (kodunuzu bozabilir) veya karmaşık hale gelebilir (kodunuzu bozabilir) veya yeterince "güveniniz" olmayabilir (kodunuzu bozabilir). Deseni görüyor musunuz?


Marc Merak ediyorum ... özel alanlara / özelliklere erişmek mümkün ancak GetValue tarafından döndürülen nesneyi doğru türü kullanarak çevirmenin bir yolu var mı?
codingadventures

1
@GiovanniCampo eğer türün ne olduğunu statik olarak biliyorsanız: elbette - sadece yayınlayın. Türü statik olarak bilmiyorsanız - bunun ne anlama geldiği
Marc Gravell

Genel API'nin gerçekten parçası olan şeyleri dahili olarak yayınlayan insanlara ne olacak? Veya kullandılar InternalsVisibleToama montajınızı içermediler mi? Sembol gerçekten gizli değilse, ABI'nin bir parçasıdır.
binki

208

İç üyelerinizin başka bir meclise maruz kalmasına izin vereceğiniz ve test amaçlı olan tek bir durum görüyorum.

"Arkadaş" meclislerinin dahili bileşenlere erişmesine izin vermenin bir yolu olduğunu söyleyerek:

Projenin AssemblyInfo.cs dosyasında her derleme için bir satır eklersiniz.

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

bu bilgi burada mevcuttur .

Bu yardımcı olur umarım.


Test amaçlarına ilişkin genişleme. Farklı bağlamlarda dahili öğeleri birleştirdiğiniz herhangi bir senaryo. Örneğin, Unity'de bir çalışma zamanı derlemeniz, bir test derlemeniz ve bir düzenleyici derlemeniz olabilir. Çalışma zamanı dahili öğeleri, test ve düzenleyici derlemeleri için görünür olmalıdır.
Steve Buzonas

3
Bu cevabın yardımcı olduğunu sanmıyorum - OP satıcının montajını değiştiremeyeceğini söylüyor ve bu cevap satıcının projesinin AssemblyInfo.cs dosyasını değiştirmekten bahsediyor
Simon Green

6

Mono.Cecil kullanarak, orijinal montajı genişletemeyeceğiniz bir noktayı öne [InternalsVisibleTo(...)]sürmek istiyorum. 3pty montajına enjekte edebilirsiniz . Yasal çıkarımlar olabileceğini unutmayın - 3pty montajı ve teknik çıkarımlarıyla uğraşıyorsunuz - derlemenin güçlü adı varsa ya onu çıkarmanız ya da farklı bir anahtarla yeniden imzalamanız gerekir.

 Install-Package Mono.Cecil

Ve kod şöyle:

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

1
Benim için değiştirilemez, bir nugetten geldiği anlamına gelir ve değişikliklerle yerel bir nuget oluşturmak ve yönetmek zorunda kalmak istemiyorum. Ayrıca, bazı insanlar için güçlü bir ismin kaybı önemli olacaktır. Ama bu ilginç bir nokta.
binki

3

Yansıma.

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

Gücü akıllıca kullanın. Hata kontrolünü unutmayın. :)


-2

Yapamazsın. Dahili sınıflar derlemelerinin dışında görünemez, bu nedenle doğrudan ona erişmenin açık bir yolu yoktur -AFAIK elbette. Tek yol, yansıtma yoluyla çalışma zamanı geç bağlamayı kullanmaktır, ardından dolaylı olarak iç sınıftan yöntemleri ve özellikleri çağırabilirsiniz.


5
Düşünceli her şeyi arayabilirsiniz
MrHinsh - Martin Hinshelwood
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.