尝试在动态创建的程序集上绑定动态方法会导致RuntimeBinderException
问题描述:
我有一个方便的实用程序方法,它需要代码并将内存程序集分出。 (它使用CSharpCodeProvider
,虽然我不认为应该没关系。)该组件像任何其他与反思,但与dynamic
关键字使用时,它似乎无法用RuntimeBinderException
:尝试在动态创建的程序集上绑定动态方法会导致RuntimeBinderException
“对象”不包含“声音”的定义
例子:
var assembly = createAssembly("class Dog { public string Sound() { return \"woof\"; } }");
var type = assembly.GetType("Dog");
Object dog = Activator.CreateInstance(type);
var method = type.GetMethod("Sound");
var test1Result = method.Invoke(dog, null); //This returns "woof", as you'd expect
dynamic dog2 = dog;
String test2Result = dog2.Sound(); //This throws a RuntimeBinderException
有谁知道为什么DLR是无法处理这种情况的原因?有什么可以解决这个问题吗?
编辑:
createAssembly方法:
免责声明:一些这方面的东西包含扩展方法,自定义类型等,这应该是不言自明,但。
private Assembly createAssembly(String source, IEnumerable<String> assembliesToReference = null)
{
//Create compiler
var codeProvider = new CSharpCodeProvider();
//Set compiler parameters
var compilerParameters = new CompilerParameters
{
GenerateInMemory = true,
GenerateExecutable = false,
CompilerOptions = "/optimize",
};
//Get the name of the current assembly and everything it references
if (assembliesToReference == null)
{
var executingAssembly = Assembly.GetExecutingAssembly();
assembliesToReference = executingAssembly
.AsEnumerable()
.Concat(
executingAssembly
.GetReferencedAssemblies()
.Select(a => Assembly.Load(a))
)
.Select(a => a.Location);
}//End if
compilerParameters.ReferencedAssemblies.AddRange(assembliesToReference.ToArray());
//Compile code
var compilerResults = codeProvider.CompileAssemblyFromSource(compilerParameters, source);
//Throw errors
if (compilerResults.Errors.Count != 0)
{
throw new CompilationException(compilerResults.Errors);
}
return compilerResults.CompiledAssembly;
}
答
让你public
类。
var assembly = createAssembly("public class Dog { public string Sound() ...
^
这解决了我的机器上的问题。
答
这可能是一个工作周期。
//instead of this
//dynamic dog2 = dog;
//try this
dynamic dog2 = DynWrapper(dog);
String test2Result = dog2.Sound();//Now this works.
public class DynWrapper : DynamicObject {
private readonly object _target;
public DynWrapper(object target) {
_target = target;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) {
//for the sake of simplicity I'm not taking arguments into account,
//of course you should in a real app.
var mi = _target.GetType().GetMethod(binder.Name);
if (mi != null) {
result = mi.Invoke(_target, null);
return true;
}
return base.TryInvokeMember(binder, args, out result);
}
}
PS:我尝试发布此为注释(因为它是一个workarround不是一个答案),但不能这样做怎么一回事,因为它的长....
我的部分愚蠢的错误。 'dynamic'尊重可访问性,所以它不能从另一个程序集执行非公共代码,而反射并不关心可访问性。谢谢。 – MgSam