如何从外部程序集访问内部类?

有一个程序集,我不能修改(供应商提供) ,其中有一个方法返回一个 目标类型,但实际上是一个内部类型。

如何从程序集访问对象的字段和/或方法?

请记住,我不能修改供应商提供的程序集。

从本质上讲,这就是我所拥有的:

供应商:

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
}
}
144805 次浏览

如果不能访问类型(也不能访问“ InternalsVisibleTo”等) ,就必须使用反射。但是一个更好的问题是: 应该你正在访问这些数据吗?它不是公共类型契约的一部分... ... 在我看来,它似乎意在被当作一个不透明的对象(为了他们的目的,而不是你的目的)。

您已经将其描述为一个公共实例字段; 通过反射获取:

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

如果它实际上是一个属性(而不是字段) :

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

如果它是非公共的,则需要使用 GetField/GetPropertyBindingFlags重载。

重要的是 : 小心这样的反射; 实现可能在下一个版本中改变(破坏您的代码) ,或者可能被混淆(破坏您的代码) ,或者您可能没有足够的“信任”(破坏您的代码)。你发现规律了吗?

你不能。内部类不能在它们的汇编之外可见,所以没有直接访问它的显式方法——当然是 AFAIK。 唯一的方法是通过反射使用运行时后期绑定,然后您可以间接地从内部类调用方法和属性。

反射。

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

Use the power wisely. Don't forget error checking. :)

I see only one case that you would allow exposure to your internal members to another assembly and that is for testing purposes.

说明有一种方法允许“朋友”程序集访问内部构件:

在项目的 AssemblyInfo.cs 文件中,为每个程序集添加一行。

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

这个信息是可用的 here.

希望这个能帮上忙。

我想讨论一个问题——你不能使用 Mono 来扩展原来的程序集。塞西尔,你可以把 [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"))
// });
}

在.NET 5中,可以将 InternalsVisibleToAttribute 添加到.csproj:

<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
<_Parameter1>Core.Tests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>