C# 如何从外部程序集访问内部类?
具有我无法修改的程序集(供应商提供),该程序集的方法返回对象类型,但实际上是内部类型 如何从程序集中访问对象的字段和/或方法 请记住,我无法修改供应商提供的程序集C# 如何从外部程序集访问内部类?,c#,class,C#,Class,具有我无法修改的程序集(供应商提供),该程序集的方法返回对象类型,但实际上是内部类型 如何从程序集中访问对象的字段和/或方法 请记住,我无法修改供应商提供的程序集 public class MyClass { public void AccessTest() { Vendor vendor = new Vendor(); object value = vendor.Tag; // Here I want to access InternalClass.test
public class MyClass
{
public void AccessTest()
{
Vendor vendor = new Vendor();
object value = vendor.Tag;
// Here I want to access InternalClass.test
}
}
[assembly: InternalsVisibleTo("name of assembly here")]
本质上,我拥有的是:
来自供应商:
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
}
}
[assembly: InternalsVisibleTo("name of assembly here")]
如果无法访问该类型(并且没有“InternalsVisibleTo”等),则必须使用反射。但更好的问题是:您是否应该访问这些数据?它不是公共类型合同的一部分。。。对我来说,这听起来像是要被当作一个不透明的物体来对待(出于他们的目的,而不是你的目的) 您已经将其描述为公共实例字段;要通过反射获取此信息,请执行以下操作:
object obj = ...
string value = (string)obj.GetType().GetField("test").GetValue(obj);
如果它实际上是一个属性(不是字段):
如果它是非公共的,则需要使用GetField
/GetProperty
的BindingFlags
重载
重要的旁白:小心这样的思考;实现可能会在下一个版本中更改(破坏代码),也可能会混淆(破坏代码),或者您可能没有足够的“信任”(破坏代码)。你发现模式了吗?嗯,你不能。内部类在其程序集之外不可见,因此没有直接访问它的显式方法——当然是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);
明智地使用权力。不要忘记错误检查。:) 我只看到一种情况,您允许将内部成员暴露于另一个程序集,这是出于测试目的 表示有一种方法允许“友元”程序集访问内部: 在项目的AssemblyInfo.cs文件中,为每个部件添加一行
public class MyClass
{
public void AccessTest()
{
Vendor vendor = new Vendor();
object value = vendor.Tag;
// Here I want to access InternalClass.test
}
}
[assembly: InternalsVisibleTo("name of assembly here")]
此信息可用
希望这能有所帮助。我想提出一点——您不能扩充原始程序集——使用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"))
// });
}
你可以使用reflectionMarc调用任何东西,我想知道……可以访问私有字段/属性,但是有没有办法使用正确的类型强制转换GetValue返回的对象?@GiovanniCampo,如果你静态地知道类型是什么:当然-只需强制转换即可。如果您不知道静态的类型,那么我们甚至不清楚这意味着什么,对于那些将内容发布为内部构件(实际上是公共API的一部分)的人来说,这意味着什么?或者他们使用了
InternalsVisibleTo
,但没有包含您的程序集?如果这个符号不是真正隐藏的,它就是ABI的一部分。对我来说,不能修改意味着它来自一个nuget,我不想通过修改创建和管理一个本地nuget。此外,对一些人来说,失去一个强有力的名字也很重要。但这是一个有趣的观点。扩展到测试目的的情况。在不同上下文中耦合内部构件的任何场景。例如,在Unity中,您可能有一个运行时程序集、一个测试程序集和一个编辑器程序集。运行时内部应该对测试和编辑器程序集可见。我认为这个答案没有帮助-OP说他不能修改供应商的程序集,这个答案涉及修改供应商项目的AssemblyInfo.cs文件