Pertanyaan C # - Bagaimana mengakses kelas internal dari perakitan eksternal


Memiliki rakitan yang tidak dapat saya modifikasi (disediakan vendor) yang memiliki metode mengembalikan obyek ketik tetapi benar-benar dari tipe internal.

Bagaimana saya bisa mengakses bidang dan / atau metode objek dari perakitan saya?

Perlu diingat bahwa saya tidak dapat memodifikasi rakitan yang dipasok oleh vendor.

Intinya, inilah yang saya miliki:

Dari vendor:

internal class InternalClass
  public string test;
end class

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

Dari rakitan saya menggunakan rakitan vendor.

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


asal


Jawaban:


Tanpa akses ke jenis (dan tidak ada "InternalVisibleTo" dll) Anda harus menggunakan refleksi. Tapi pertanyaan yang lebih baik adalah: harus Anda akan mengakses data ini? Ini bukan bagian dari kontrak tipe publik ... kedengarannya bagi saya seperti itu dimaksudkan untuk diperlakukan sebagai objek buram (untuk tujuan mereka, bukan milik Anda).

Anda telah menggambarkannya sebagai bidang contoh publik; untuk mendapatkan ini melalui refleksi:

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

Jika sebenarnya adalah properti (bukan bidang):

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

Jika tidak umum, Anda harus menggunakan BindingFlags kelebihan muatan GetField/GetProperty.

Penting disisihkan: hati-hati dengan refleksi seperti ini; penerapannya dapat berubah di versi berikutnya (melanggar kode Anda), atau bisa jadi tidak jelas (melanggar kode Anda), atau Anda mungkin tidak memiliki cukup "kepercayaan" (melanggar kode Anda). Apakah Anda menemukan pola?


74
2018-05-28 13:32



Saya hanya melihat satu kasus yang memungkinkan Anda untuk memaparkan anggota internal Anda ke perakitan lain dan itu untuk tujuan pengujian.

Mengatakan bahwa ada cara untuk mengizinkan akses "Teman" ke internal:

Dalam file AssemblyInfo.cs dari proyek Anda menambahkan baris untuk setiap perakitan.

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

info ini tersedia sini.

Semoga ini membantu.


181
2018-06-12 00:52



Refleksi.

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

Gunakan kekuatan dengan bijaksana. Jangan lupa memeriksa kesalahan. :)


3
2018-05-28 13:34



Saya ingin berdebat satu titik - bahwa Anda tidak dapat menambah perakitan asli - menggunakan Mono.Cecil Anda dapat menyuntikkan [InternalsVisibleTo(...)] ke majelis 3pty. Perhatikan mungkin ada implikasi hukum - Anda mengacaukan dengan 3pty assembly dan implikasi teknis - jika majelis memiliki nama kuat Anda perlu melucurkannya atau menandatanganinya kembali dengan kunci yang berbeda.

 Install-Package Mono.Cecil

Dan kode seperti:

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



Yah, kamu tidak bisa. Kelas internal tidak dapat terlihat di luar pertemuan mereka, jadi tidak ada cara eksplisit untuk mengaksesnya secara langsung -AFAIK tentu saja. Satu-satunya cara adalah dengan menggunakan runtime late-binding melalui refleksi, maka Anda dapat memanggil metode dan properti dari kelas internal secara tidak langsung.


-3
2018-05-28 13:34