有一个我无法修改的程序集(供应商提供),它有一个方法返回 对象 类型,但实际上是内部类型。
如何从程序集中访问对象的字段和/或方法?
请记住,我无法修改供应商提供的程序集。
从本质上讲,这就是我所拥有的:
来自供应商:
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
}
}
答案 0 :(得分:196)
我只看到一个案例,允许您将内部成员暴露给另一个程序集,这是出于测试目的。
说有一种方法允许“朋友”程序集访问内部:
在项目的AssemblyInfo.cs文件中,为每个程序集添加一行。
[assembly: InternalsVisibleTo("name of assembly here")]
此信息可用here.
希望这有帮助。
答案 1 :(得分:77)
如果不访问类型(并且没有“InternalsVisibleTo”等),则必须使用反射。但更好的问题是: 你应该访问这些数据吗?它不是公共类型合同的一部分...它听起来像是打算被视为一个不透明的对象(为了他们的目的,而不是你的目的)。
您已将其描述为公共实例字段;通过反思得到这个:
object obj = ...
string value = (string)obj.GetType().GetField("test").GetValue(obj);
如果它实际上是属性(不是字段):
string value = (string)obj.GetType().GetProperty("test").GetValue(obj,null);
如果是非公开的,则需要使用BindingFlags
/ GetField
的{{1}}重叠。
重要的是:小心这样的反思;实现可能会在下一个版本中发生变化(破坏您的代码),或者它可能会被混淆(破坏您的代码),或者您可能没有足够的“信任”(破坏您的代码)。你是否发现了这种模式?
答案 2 :(得分:5)
我想争论一点 - 你无法扩充原始程序集 - 使用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 :(得分:3)
反射。
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 :(得分:-2)