C# 内存中的反射和动态程序集
假设我使用CSharpCodeProvider动态创建了一个类型,并选择不持久化结果。生成的程序集仅存在于内存中。 假设我在两个不同的内存程序集中创建了两种类型: 大会1:C# 内存中的反射和动态程序集,c#,reflection,C#,Reflection,假设我使用CSharpCodeProvider动态创建了一个类型,并选择不持久化结果。生成的程序集仅存在于内存中。 假设我在两个不同的内存程序集中创建了两种类型: 大会1: public class DynamicTypeA { } 大会2: public class DynamicTypeB { public DynamicTypeA MyProperty { get; set; } } 如您所见,第二种类型具有第一种类型的属性。 酷。现在,我想使用反射探索DynamicTy
public class DynamicTypeA { }
大会2:
public class DynamicTypeB
{
public DynamicTypeA MyProperty { get; set; }
}
如您所见,第二种类型具有第一种类型的属性。
酷。现在,我想使用反射探索DynamicTypeB:
foreach (PropertyInfo pi in typeof(DynamicTypeB).GetProperties())
{
Console.WriteLine(pi.PropertyType.Name);
}
当程序集不在磁盘上时,PropertyInfo.PropertyType会失败!!!
MemberInfo和所有其他类型调查构造都是如此
众所周知,许多.Net API在后端使用类型调查,当调查的类型恰好位于内存程序集中时,它们将失败。例如Expression.Bind将MemberInfo作为第一个参数,并使用它验证第二个参数中提供的表达式类型是否与成员类型匹配。当此类型恰好位于内存中的程序集表达式中时。绑定失败
有人能想出解决办法吗
动态创建类型并将其写入磁盘会污染运行环境,这是不好的,但如果没有反射,这些类型将一文不值
谢谢
马努
当程序集不在磁盘上时,PropertyInfo.PropertyType会失败
你确定吗?看一看:
static void Main( string[] args )
{
string code = @"
namespace foo {
public class DynamicTypeA { }
public class DynamicTypeB {
public DynamicTypeA MyProperty { get; set; }
}
}
";
CSharpCodeProvider csp = new CSharpCodeProvider();
CompilerParameters p = new CompilerParameters();
p.GenerateInMemory = true;
var results = csp.CompileAssemblyFromSource( p, code );
foreach ( Type type in results.CompiledAssembly.GetTypes() )
{
Console.WriteLine( type.Name );
foreach ( PropertyInfo pi in type.GetProperties() )
{
Console.WriteLine( "\t{0}", pi.PropertyType.Name );
}
}
Console.ReadLine();
}
这使用了你的代码片段,效果很好
将循环移动到动态代码内部不会有太大变化,它仍然有效:
string code = @"
using System;
using System.Reflection;
namespace foo {
public class DynamicTypeA { }
public class DynamicTypeB {
public DynamicTypeA MyProperty { get; set; }
}
public class DynamicTypeC {
public void Foo() {
foreach ( PropertyInfo pi in typeof(DynamicTypeB).GetProperties() )
{
Console.WriteLine( pi.PropertyType.Name );
}
}
}
}
";
CSharpCodeProvider csp = new CSharpCodeProvider();
CompilerParameters p = new CompilerParameters();
p.GenerateInMemory = true;
var results = csp.CompileAssemblyFromSource( p, code );
var c = results.CompiledAssembly.CreateInstance( "foo.DynamicTypeC" );
var typeC = c.GetType();
typeC.InvokeMember( "Foo", BindingFlags.InvokeMethod |
BindingFlags.Public | BindingFlags.Instance, null, c, null );
如果出于某种原因,您在这里遇到了问题,那么您肯定是在做更复杂的事情。我发现了问题:
我需要将动态编译的程序集加载到当前AppDomain中,只有这样,我才能通过反射检索任何信息
我要感谢Sam Alavi向我解释这一点。
以下是带有必要修复的代码:
public class HomeController : Controller
{
public Assembly AssemblyA { get; set; }
public Assembly AssemblyB { get; set; }
public ActionResult Index()
{
var provider = new CSharpCodeProvider();
var parametersA = new CompilerParameters();
parametersA.GenerateInMemory = true;
parametersA.OutputAssembly = "dynamicA.dll";
var code1 = @"namespace DynamicA { public class DynamicClassA { } }";
var result1 = provider.CompileAssemblyFromSource(parametersA, code1);
this.AssemblyA = result1.CompiledAssembly;
var parametersB = new CompilerParameters();
parametersA.GenerateInMemory = true;
parametersB.ReferencedAssemblies.Add("dynamicA.dll");
parametersB.OutputAssembly = "dynamicB.dll";
var code2 = @"using DynamicA; namespace DynamicB { public class DynamicB { public DynamicClassA MyProperty { get; set; } } }";
var results2 = provider.CompileAssemblyFromSource(parametersB, code2);
this.AssemblyB = results2.CompiledAssembly;
AppDomain.CurrentDomain.AssemblyResolve += (sender, e) =>
{
if (e.Name.Contains("dynamicA"))
return this.AssemblyA;
if (e.Name.Contains("dynamicB"))
return this.AssemblyB;
return null;
};
AppDomain.CurrentDomain.Load(this.AssemblyA.FullName);
AppDomain.CurrentDomain.Load(this.AssemblyB.FullName);
var t = results2.CompiledAssembly.DefinedTypes.First();
var pi = t.GetProperty("MyProperty");
var res = pi.PropertyType.Name;
return View(res);
}
}