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

Sté*_*écy 93 c# class

有一个我无法修改的程序集(供应商提供),它有一个方法返回一个对象类型,但实际上是一个内部类型.

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

请记住,我无法修改供应商提供的程序集.

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

来自供应商:

internal class InternalClass
  public string test;
end class

public class Vendor
  private InternalClass _internal;
  public object Tag {get{return _internal;}}
end class
Run Code Online (Sandbox Code Playgroud)

从我使用供应商组件的装配.

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

zon*_*lut 203

我只看到一个案例,你允许你的内部成员接触另一个组件,这是为了测试目的.

说有一种方法允许"朋友"程序集访问内部:

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

[assembly: InternalsVisibleTo("name of assembly here")]
Run Code Online (Sandbox Code Playgroud)

此信息可在此处获得.

希望这可以帮助.

  • 我不认为这个答案有帮助 - OP说他不能修改供应商的程序集,这个答案谈到修改供应商项目的AssemblyInfo.cs文件 (3认同)

Mar*_*ell 82

如果没有访问类型(并且没有"InternalsVisibleTo"等),则必须使用反射.但是,一个更好的问题是:应该你可以访问这些数据?它不是公共类型合同的一部分......它听起来像我的意图被视为一个不透明的对象(为了他们的目的,而不是你的目的).

您已将其描述为公共实例字段; 通过反思得到这个:

object obj = ...
string value = (string)obj.GetType().GetField("test").GetValue(obj);
Run Code Online (Sandbox Code Playgroud)

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

string value = (string)obj.GetType().GetProperty("test").GetValue(obj,null);
Run Code Online (Sandbox Code Playgroud)

如果它是非公开的,您将需要使用/ 的BindingFlags重载.GetFieldGetProperty

重要的是:小心这样的反思; 实现可能会在下一个版本中发生变化(破坏您的代码),或者它可能会被混淆(破坏您的代码),或者您可能没有足够的"信任"(破坏您的代码).你是否发现了这种模式?


Dam*_*ski 13

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

<ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
      <_Parameter1>Core.Tests</_Parameter1>
    </AssemblyAttribute>
</ItemGroup>
Run Code Online (Sandbox Code Playgroud)


Ond*_*dar 5

我想争论一点 - 你无法增加原始程序集 - 使用Mono.Cecil你可以注入[InternalsVisibleTo(...)]3pty程序集.请注意,可能存在法律含义 - 您正在搞乱3pty汇编和技术含义 - 如果程序集具有强名称,您需要将其删除或使用不同的密钥重新签名.

 Install-Package Mono.Cecil
Run Code Online (Sandbox Code Playgroud)

代码如下:

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"))
   // });
}
Run Code Online (Sandbox Code Playgroud)

  • 对我来说,无法修改意味着它来自 nuget,我不想通过修改创建和管理本地 nuget。此外,对于某些人来说,失去响亮的名字也很重要。但这是一个有趣的点。 (2认同)