Как я могу получить доступ к внутреннему классу из внешней сборки? - PullRequest
88 голосов
/ 28 мая 2009

Имеет сборку, которую я не могу изменить (предоставленную поставщиком), в которой есть метод, возвращающий тип объект , но на самом деле он имеет внутренний тип.

Как получить доступ к полям и / или методам объекта из моей сборки?

Имейте в виду, что я не могу изменить сборку, поставляемую поставщиком.

По сути, вот что у меня есть:

От продавца:

internal class InternalClass
  public string test;
end class

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

Из моей сборки, используя сборку поставщика.

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

Ответы [ 5 ]

196 голосов
/ 12 июня 2009

Я вижу только один случай, когда вы позволите своим внутренним элементам подвергаться воздействию другой сборки, и это для целей тестирования.

Сказать, что есть способ разрешить сборкам "Друг" доступ к внутренним компонентам:

В файле AssemblyInfo.cs проекта вы добавляете строку для каждой сборки.

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

эта информация доступна здесь.

Надеюсь, это поможет.

77 голосов
/ 28 мая 2009

Без доступа к типу (без «InternalsVisibleTo» и т. Д.) Вам пришлось бы использовать отражение. Но лучше задать вопрос: должен ли обращаться к этим данным? Он не является частью публичного типа контракта ... для меня это звучит так, как будто он предназначен для обработки как непрозрачный объект (для их целей, а не для ваших).

Вы описали его как публичное поле экземпляра; чтобы получить это через отражение:

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

Если это действительно свойство (а не поле):

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

Если это не публично, вам нужно использовать перегрузку BindingFlags GetField / GetProperty.

Важное замечание : будьте осторожны с таким отражением; реализация может измениться в следующей версии (нарушить ваш код), или она может быть запутана (нарушить ваш код), или вам может не хватить «доверия» (нарушить ваш код). Вы видите образец?

5 голосов
/ 02 июня 2017

Я бы хотел поспорить с одним замечанием - что вы не можете увеличить исходную сборку - используя Mono.Cecil, вы можете вставить [InternalsVisibleTo(...)] в сборку 3pty. Обратите внимание, что могут быть юридические последствия - вы портите сборку 3pty и технические последствия - если сборка имеет строгое имя, вам нужно либо удалить ее, либо заново подписать ее другим ключом.

 Install-Package Mono.Cecil

И код вроде:

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 голосов
/ 28 мая 2009

Reflection.

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

Используйте силу с умом. Не забудьте проверить ошибки. :)

0 голосов
/ 28 мая 2009

Ну, ты не можешь. Внутренние классы не могут быть видны за пределами их сборки, поэтому нет явного способа получить к нему прямой доступ - конечно, AFAIK. Единственный способ - использовать позднее связывание во время выполнения с помощью отражения, тогда вы можете косвенно вызывать методы и свойства из внутреннего класса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...