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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/920844/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 03:13:53  来源:igfitidea点击:

How can I access an internal class from an external assembly?

c#class

提问by Stécy

Having an assembly which I cannot modify (vendor-supplied) which have a method returning an objecttype but is really of an internal type.

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

How can I access the fields and/or methods of the object from my assembly?

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

Keep in mind that I cannot modify the vendor-supplied assembly.

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

In essence, here's what I have:

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

From vendor:

来自供应商:

internal class InternalClass
  public string test;
end class

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

From my assembly using the vendor assembly.

从我使用供应商程序集的程序集。

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

采纳答案by Marc Gravell

Without access to the type (and no "InternalsVisibleTo" etc) you would have to use reflection. But a better question would be: shouldyou be accessing this data? It isn't part of the public type contract... it sounds to me like it is intended to be treated as an opaque object (for their purposes, not yours).

如果无法访问类型(并且没有“InternalsVisibleTo”等),您将不得不使用反射。但是,一个更好的问题是:应该你可以访问这些数据?它不是公共类型合同的一部分......在我看来,它旨在被视为一个不透明的对象(出于他们的目的,而不是你的目的)。

You've described it as a public instance field; to get this via reflection:

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

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

If it is actually a property (not a field):

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

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

If it is non-public, you'll need to use the BindingFlagsoverload of GetField/GetProperty.

如果它是非公开的,则需要使用/的BindingFlags重载。GetFieldGetProperty

Important aside: be careful with reflection like this; the implementation could change in the next version (breaking your code), or it could be obfuscated (breaking your code), or you might not have enough "trust" (breaking your code). Are you spotting the pattern?

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

回答by Galilyou

Well, you can't. Internal classes can't be visible outside of their assembly, so no explicit way to access it directly -AFAIK of course. The only way is to use runtime late-binding via reflection, then you can invoke methods and properties from the internal class indirectly.

嗯,你不能。内部类在其程序集之外是不可见的,因此没有直接访问它的显式方法 - 当然是 AFAIK。唯一的方法是通过反射使用运行时后期绑定,然后您可以从内部类间接调用方法和属性。

回答by Colin Burnett

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

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

明智地使用权力。不要忘记错误检查。:)

回答by zonkflut

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

我只看到一种情况,您允许将内部成员暴露给另一个程序集,这是出于测试目的。

Saying that there is a way to allow "Friend" assemblies access to internals:

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

In the AssemblyInfo.cs file of the project you add a line for each assembly.

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

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

this info is available here.

此信息可在此处获得。

Hope this helps.

希望这可以帮助。

回答by Ondrej Svejdar

I would like to argue one point - that you cannot augment the original assembly - using Mono.Cecil you can inject [InternalsVisibleTo(...)]to the 3pty assembly. Note there might be legal implications - you're messing with 3pty assembly and technical implications - if the assembly has strong name you either need to strip it or re-sign it with different key.

我想争论一点——你不能增加原始程序集——使用 Mono.Cecil 你可以注入[InternalsVisibleTo(...)]3pty 程序集。请注意,可能存在法律问题 - 您正在处理 3pty 程序集和技术问题 - 如果程序集具有强名称,则您需要将其剥离或使用不同的密钥重新签名。

 Install-Package Mono.Cecil

And the code like:

代码如下:

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"))
   // });
}