С# - Как получить доступ к внутреннему классу из внешней сборки
Наличие сборки, которую я не могу изменить (поставляемый поставщиком), который имеет метод, возвращающий тип object, но на самом деле имеет внутренний тип.
Как я могу получить доступ к полям и/или методам объекта из моей сборки?
Имейте в виду, что я не могу изменить сборку, поставляемую поставщиком.
В сущности, вот что у меня есть:
От поставщика:
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
}
}
Ответы
Ответ 1
Без доступа к типу (и не "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
.
Важно в сторону: будьте осторожны с таким отражением; реализация может измениться в следующей версии (взломать ваш код), или она может быть запутана (сломать ваш код), или вам может не хватить "доверия" (нарушение вашего кода). Вы просматриваете шаблон?
Ответ 2
Я вижу только один случай, когда вы разрешаете подвергать своих внутренних членов другой сборке и это предназначено для тестирования.
Говоря о том, что есть способ разрешить сборкам "Friend" доступ к внутренним элементам:
В файле AssemblyInfo.cs проекта вы добавляете строку для каждой сборки.
[assembly: InternalsVisibleTo("name of assembly here")]
эта информация доступна здесь.
Надеюсь, что это поможет.
Ответ 3
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);
Используйте разумную силу. Не забывайте проверять ошибки.:)
Ответ 4
Я хотел бы утверждать, что вы не можете увеличить исходную сборку - используя Mono.Cecil, вы можете вставить [InternalsVisibleTo(...)]
в сборку 3pty. Обратите внимание, что могут быть юридические последствия - вы возитесь с сборкой 3-х сторон и техническими последствиями - если сборка имеет сильное имя, вам нужно либо снять ее, либо переписать ее с помощью другого ключа.
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"))
// });
}
Ответ 5
Ну, ты не можешь. Внутренние классы не могут быть видны за пределами их сборки, поэтому нет прямого доступа к нему напрямую - АФАИК, конечно.
Единственный способ - использовать позднюю привязку во время выполнения через отражение, тогда вы можете косвенно ссылаться на методы и свойства из внутреннего класса.